jsx理解
JSX和Fiber节点不是同一个东西 。
React Component 和 React Element 也不是一个东西。
从编译来看
JSX在babel中会被编译成React.createElement(这也就是为什么需要手动import React from 'react'的原因了)
但是在17之后不需要手动引入了 看这篇
如下图:

JSX并不是只能被编译为React.createElement方法,你可以通过@babel/plugin-transform-react-jsx (opens new window)插件显式告诉Babel编译时需要将JSX编译为什么函数的调用(默认为React.createElement)。
比如在preact (opens new window)这个类React库中,JSX会被编译为一个名为h的函数调用。
React.createElement
createElement(type, config, children)- type: react component类型
- config:react component 的一些属性
- children:它的子孙react component
执行步骤
-
进来createElement我们会发现它定义了一些字段,这些字段都是我们比较常用的

-
之后我们对传进来的config进行校验,我们会发现他做了几个合法性的校验,并且对相对应的变量进行赋值
- hasValidRef:对config中的ref做合法性校验
- hasValidKey:对config中的key做合法性校验

-
遍历config中的属性,将除了保留属性之外的其他属性赋值给Props(就是内部的一个中间对象)
可以看到react把,ref,key都提出来了,单独的作为
ReactElement函数的参数传递(这个下面说) -
接下来处理type中的
defaultProps,这里也能明白,因为我们经常需要给class的组件的一些参数设置默认的属性值
-
接下来我们走入
ReactElement函数可以发现,它最终返回了一个Element对象
const ReactElement = function(type, key, ref, self, source, owner, props) {......const element = {// 标记这是个 React Element$$typeof: REACT_ELEMENT_TYPE,// 这个是react component的类型type: type,key: key,ref: ref,props: props,_owner: owner,};return element;};
这里要注意,其中` $$typeof`这个参数很重要,主要是用来[isValidElement](https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/react/src/ReactElement.js#L547)函数来判断这个element是不是合法的react element
```js export function isValidElement(object) { return ( typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE ); }可以看到,
$$typeof === REACT_ELEMENT_TYPE的非null对象就是一个合法的React Element。换言之,在React中,所有JSX在运行时的返回结果(即React.createElement()的返回值)都是React Element。
React Component
在React中,我们常使用ClassComponent与FunctionComponent构建组件。
class AppClass extends React.Component { render() { return <p>111</p> }}console.log('这是ClassComponent:', AppClass);console.log('这是Element:', <AppClass/>);
function AppFunc() { return <p>222</p>;}console.log('这是FunctionComponent:', AppFunc);console.log('这是Element:', <AppFunc/>);我们可以从Demo控制台打印的对象看出,ClassComponent对应的Element的type字段为AppClass自身。
FunctionComponent对应的Element的type字段为AppFunc自身,如下所示:
{ $$typeof: Symbol(react.element), key: null, props: {}, ref: null, type: ƒ AppFunc(), _owner: null, _store: {validated: false}, _self: null, _source: null}JSX与Fiber节点
从上面的内容我们可以发现,JSX是一种描述当前组件内容的数据结构,他不包含组件schedule、reconcile、render所需的相关信息。
比如如下信息就不包括在JSX中:
- 组件在更新中的
优先级 - 组件的
state - 组件被打上的用于Renderer的
标记
这些内容都包含在Fiber节点中。
所以,在组件mount时,Reconciler根据JSX描述的组件内容生成组件对应的Fiber节点。
在update时,Reconciler将JSX与Fiber节点保存的数据对比,生成组件对应的Fiber节点,并根据对比结果为Fiber节点打上标记。