Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Element 究竟是什么? #11

Open
oliver1204 opened this issue Dec 14, 2018 · 0 comments
Open

React Element 究竟是什么? #11

oliver1204 opened this issue Dec 14, 2018 · 0 comments

Comments

@oliver1204
Copy link
Owner

oliver1204 commented Dec 14, 2018

如下一段最简单的JSX代码:

return (

	<div className="parent" onClick="this.isFunction.bind(this)">
   		<div className="children" > I am children  </div>
	</div>
)

经过babel编译后,变成下面的样子:

return React.createElement('div', {
	className: 'parent',
	onClick: this.isFunction.bind(this)
}, React.createElement('div', {
	className: 'children'
}, " I'm children"))

通过观察babel编译后的文件,我们可以发现React 在 当Render函数被调用时 会去调用React.createElement 函数生成 element, createElement一共有三个参数:

  • type 我们写的标签,比如div、span 等。
  • config 标签中的属性,没有的时候传null
  • children children中可以再次调用React.createElement函数

在react 内部,React.createElement() 调用 ReactElement() 去新创建 一个 React element. ReactElement()返回

const element = {
    // This tag allows us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    _owner: owner, // 当前节点
  };

Render.createElement 参数中的type直接赋值type,config 中的 keyref 作为重要元素单独拎出来,其余值依次挂在 props 下面。 children 也挂在了 props 下面。

经过 React 内部函数 ReactElement 处理后,我们上面的例子就变成了下面的样子(ReactElement的返回):

{
	type: 'div',
	props: {
		className: 'parent',
		onClick: this.isFunction.bind(this),
		children: {
			type: 'div',
			children: 'I am children'
		}
	}
	
}

React Element 存在的意义

  • JavaScript 对象很轻量。用对象来作为 React Element,那么 React 可以轻松的创建或销毁这些元素,而不必去太担心操作成本;
  • React 具有分析这些对象的能力,进一步,也具有分析虚拟 Dom 的能力。当改变出现时,(相比于真实 Dom)更新虚拟 Dom 的性能优势非常明显。

children 的类型

值得一提的是,react 内部对 children的处理,有这样一段代码:

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  
  const childrenLength = arguments.length - 2;
  
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

现在我们有这么一段代码:

<div class="parent">
	<Header> I am custom element </Header>
	<div>I am dom element</div>
	I do not have tags
</div>

babel 编译后:

React.createElement(
	"div", 
	{
		className: "parent",
	}, 
	React.createElement("Header", null, "I am custom element"),
	React.createElement("div", null, "I am dom element"),
)

根据源码中对children的处理,得到React.createElement的返回如下:

{
	type: 'div',
	props: {
		className: 'parent',
		children: [
			{
				type: function Header,
				props: {
					children: "I am custom element"
				}
			},
			{
				type: 'div',
				props: {
					children: "I'm dom element"
				}
			},
			I do not have tags
		]
	}
	
}

通过上面的分析 children 一般分为以下几种类型:

  1. Object
  2. 原生DOM 节点的 element
  3. react component 自定义组件的 element
  4. String
  5. 数组 - 当 children 节点数超过1个或者 children 是map 出来的list等。
  6. false, null, undefinde, number

在遇到 react component 时,type 会是一个function 或者 class。react 会先看这个 class 或函数会返回什么样的 Element,并为这个 Element 设置正确的属性。react 会一直不断重复这个过程(有点类似递归),直到没有 “createElement 调用 type 值为 class 或者 function” 的情况。

React 处理这些逻辑的过程就就属于 reconciliation 的一部分,当然完整的 reconciliation 更加复杂,涉及到的层面包括了 diff、render 等。

当我们在使用,ReactDOM.render 或者 setState 的时候,才会被渲染成真实的DOM。

image

@oliver1204 oliver1204 changed the title JSX 如何生成 element React Element 究竟是什么? Dec 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant