JSX和createElement
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(){ |
—> Babel会把上面的JSX语句转化成下面这样
function B() { |
因此,**JSX语法其实是React.createElement函数的语法糖
**。
接下来,我们看看React.createElement函数是如何工作的。
源码:
首先可以看到,createElement
方法会接受三个参数:type
, config
, children
。
由上面的例子可以看出,第一个type
属性可以为三种值:
- 当创建的元素为
HTML标签
时,type
的值是对应的字符串
- 当创建的元素为
classComponent
时,type
的值就是对应的class
- 当创建的元素为
functionComponent
时,type
的值就是对应的function
第二个config
属性存放的是标签中的属性。
第三个children
属性存放的则是被标签包裹的子元素。
接着,会使用hasValidRef
和hasValidKey
方法检查config
属性中ref
字段和key
字段的合法性。
之后会遍历config
属性,将非保留属性存储到props
中。
来让我们看看RESERVED_PROPS
保留属性究竟有些什么。
可以看到,保留属性就是我们key
和ref
等,然后将其他属性都放入了props
中。
由于children的数量可能不止一个,所以通过将arguments.length-2
的操作拿到children的个数。将所有的children元素放入数组中。保存在props.children
这个属性中。
接着,就是处理defaultProps
的操作,从上文,我们知道type
中保存的是组件对应的class
和function
。
从type中取出defaultProps,将默认值赋值到对应的props属性上。
之后返回一个ReactElement
补充:
React中有一个isValidElement的方法来判断一个元素是否是一个合法的Element元素。
这个方法判断过程如源码所示:
- 首先是判断元素时候是一个对象或者是否为null。
- 如果元素不为null,且是一个对象,之后判断这个对象上的
$$typeof
属性是否等于REACT_ELEMENT_TYPE
从上面的React.createElement
源码中可以看到,只要一个元素,是createElement方法生成的,就一定是个合法的Element元素。
JSX和Fiber的关系
创建Fiber节点的依据就是JSX返回的Element对象
参考:
React源码17.0.2