JSX
和Fiber节点
是同一个东西么?React Component
、React Element
是同一个东西么,他们和JSX
有什么关系?
带着这些疑问,让我们开始这一节的学习。
相信作为React
的使用者,你已经接触过JSX
。如果你还不了解他,可以看下。
JSX
在编译时会被Babel
编译为React.createElement
方法。
JSX编译
关注公众号,后台回复712获得在线Demo地址
这也是为什么在每个使用JSX
的JS文件中,你必须显式的声明
否则在运行时该模块内就会报未定义变量 React
的错误。
注意
在React17中,已经不需要显式导入React了。详见
比如在preact (opens new window)这个类React
库中,JSX
会被编译为一个名为h
的函数调用。
// 编译前
<p>KaSong</p>
// 编译后
h("p", null, "KaSong");
既然JSX
会被编译为React.createElement
,让我们看看他做了什么:
我们可以看到,React.createElement
最终会调用ReactElement
方法返回一个包含组件数据的对象,该对象有个参数$$typeof: REACT_ELEMENT_TYPE
标记了该对象是个React Element
。
所以调用React.createElement
返回的对象就是么?
React
提供了验证合法React Element
的全局API React.isValidElement (opens new window),我们看下他的实现:
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}
可以看到,$$typeof === REACT_ELEMENT_TYPE
的非null
对象就是一个合法的React Element
。换言之,在React
中,所有JSX
在运行时的返回结果(即React.createElement()
的返回值)都是React Element
。
那么JSX
和React Component
的关系呢?
在React
中,我们常使用ClassComponent
与FunctionComponent
构建组件。
React Component 分类 Demo
我们可以从Demo控制台打印的对象看出,ClassComponent
对应的Element
的type
字段为AppClass
自身。
FunctionComponent
对应的Element
的type
字段为AppFunc
自身,如下所示:
{
$$typeof: Symbol(react.element),
key: null,
type: ƒ AppFunc(),
_owner: null,
_store: {validated: false},
_self: null,
_source: null
}
值得注意的一点,由于
所以无法通过引用类型区分ClassComponent
和FunctionComponent
。React
通过ClassComponent
实例原型上的isReactComponent
变量判断是否是ClassComponent
。
ClassComponent.prototype.isReactComponent = {};
从上面的内容我们可以发现,JSX
是一种描述当前组件内容的数据结构,他不包含组件schedule、reconcile、render所需的相关信息。
比如如下信息就不包括在JSX
中:
- 组件在更新中的
优先级
- 组件的
state
- 组件被打上的用于Renderer的
标记
这些内容都包含在Fiber节点
中。
所以,在组件mount
时,Reconciler
根据JSX
描述的组件内容生成组件对应的Fiber节点
。
在update
时,Reconciler
将JSX
与Fiber节点
保存的数据对比,生成组件对应的Fiber节点
,并根据对比结果为Fiber节点
打上标记
。