JSX是一个 JavaScript 的语法扩展,在编译阶段被babel编译成为 React.createElement()
函数调用。
所以会在jsx文件中 引入React , import React from ‘react’;
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
React DOM 在渲染所有输入内容之前,默认会进行转义。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击
JSX本质上就是一个JS对象,对象中包含了type、key、props、ref等属性
React.createElement
export function createElement(type, config, children) {
let propName;
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
if (config != null) {
// 将 config 处理后赋值给 props
// ...省略
}
const childrenLength = arguments.length - 2;
// 处理 children,会被赋值给props.children
// ...省略
// 处理 defaultProps
// ...省略
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// 标记这是个 React Element
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: ref,
props: props,
_owner: owner,
};
return element;
};
可以看到,React.createElement
最终会调用ReactElement
方法返回一个包含组件数据的对象,该对象有个参数$$typeof: REACT_ELEMENT_TYPE
标记了该对象是个React Element
。
JSX与Fiber
JSX
是一种描述当前组件内容的数据结构,不包含组件schedule、reconcile、render所需的相关信息。
如下信息就不包括在JSX
中:
- 组件在更新中的
优先级
- 组件的
state
- 组件被打上的用于Renderer的
标记
这些内容都包含在Fiber节点
中。
所以,在组件mount
时,Reconciler
根据JSX
描述的组件内容生成组件对应的Fiber节点
。
在update
时,Reconciler
将JSX
与Fiber节点
保存的数据对比,生成组件对应的Fiber节点
,并根据对比结果为Fiber节点
打上标记