const element = <h1>Hello, world!</h1>;

这个有趣的标签语法既不是字符串也不是 HTML。

它被称为 JSX,是一个 JavaScript 的语法扩展。

在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。

JSX 可以生成 React “元素”。

为什么使用 JSX?

React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。

React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离

JSX 表示对象

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。

function B(){
return (
<div></div>
)
}
class A extends React.Component{
render() {
return (
<div></div>
)
}
}
<div>
<div className="tage"></div>
<A/>
<B/>
</div>

—> Babel会把上面的JSX语句转化成下面这样

function B() {
return /*#__PURE__*/React.createElement("div", null);
}

class A extends React.Component {
render() {
return /*#__PURE__*/React.createElement("div", null);
}

}

/*#__PURE__*/
React.createElement("div", null,
/*#__PURE__*/React.createElement("div", {className: "tage"}),
/*#__PURE__*/React.createElement(A, null),
/*#__PURE__*/React.createElement(B, null)
);

因此,**JSX语法其实是React.createElement函数的语法糖**。

接下来,我们看看React.createElement函数是如何工作的。


源码:

image-20220708142335834

首先可以看到,createElement方法会接受三个参数:type, config, children

由上面的例子可以看出,第一个type属性可以为三种值:

  • 当创建的元素为HTML标签时,type的值是对应的字符串
  • 当创建的元素为classComponent时,type的值就是对应的class
  • 当创建的元素为functionComponent时,type的值就是对应的function

第二个config属性存放的是标签中的属性。

第三个children属性存放的则是被标签包裹的子元素。

image-20220708142955895

接着,会使用hasValidRefhasValidKey方法检查config属性中ref字段和key字段的合法性。

image-20220708143149826

之后会遍历config属性,将非保留属性存储到props中。

来让我们看看RESERVED_PROPS保留属性究竟有些什么。

image-20220708143305903

可以看到,保留属性就是我们keyref等,然后将其他属性都放入了props中。

由于children的数量可能不止一个,所以通过将arguments.length-2的操作拿到children的个数。将所有的children元素放入数组中。保存在props.children这个属性中。

image-20220708143755451

接着,就是处理defaultProps的操作,从上文,我们知道type中保存的是组件对应的classfunction

从type中取出defaultProps,将默认值赋值到对应的props属性上。

image-20220708143859838

之后返回一个ReactElement

image-20220708144106163

image-20220708144139712


补充:

React中有一个isValidElement的方法来判断一个元素是否是一个合法的Element元素。

这个方法判断过程如源码所示:

  • 首先是判断元素时候是一个对象或者是否为null。
  • 如果元素不为null,且是一个对象,之后判断这个对象上的$$typeof属性是否等于REACT_ELEMENT_TYPE

image-20220708144416915

从上面的React.createElement源码中可以看到,只要一个元素,是createElement方法生成的,就一定是个合法的Element元素。


JSX和Fiber的关系

创建Fiber节点的依据就是JSX返回的Element对象


参考: