JSX
最重要的 React.createElement 函数的用法:
React.createElement(
type,
[props],
[...children]
)
- 第一个参数:如果是组件类型,会传入组件对应的类或函数;如果是 dom 元素类型,传入 div 或者 span 之类的字符串。
- 第二个参数:一个对象,在 dom 类型中为标签属性,在组件类型中为 props 。
- 其他参数:依次为 children,根据顺序排列。
JSX的转换规则:
element—>react element
fragment—>react element
文本类型—> 直接字符串
数组类型—> 返回数组结构,里面元素被react.createElement转换
组件类型—> react element
等等.......
经过React调和后JSX最终会变成一个fiber的结构图:
React element 对象的每一个子节点都会形成一个与之对应的 fiber 对象,然后通过 sibling、return、child 将每一个 fiber 对象联系起来,如此便可形成一张图结构。
- child: 一个由父级 fiber 指向子级 fiber 的指针。
- return:一个子级 fiber 指向父级 fiber 的指针。
- sibling: 一个 fiber 指向下一个兄弟 fiber 的指针。
并且React 针对不同 React element 对象会产生不同 tag 的fiber 对象。
下面便是tag与element之间的关系:
export const FunctionComponent = 0; // 函数组件
export const ClassComponent = 1; // 类组件
export const IndeterminateComponent = 2; // 初始化的时候不知道是函数组件还是类组件
export const HostRoot = 3; // Root Fiber 可以理解为根元素 , 通过reactDom.render()产生的根元素
export const HostPortal = 4; // 对应 ReactDOM.createPortal 产生的 Portal
export const HostComponent = 5; // dom 元素 比如 <div>
export const HostText = 6; // 文本节点
export const Fragment = 7; // 对应 <React.Fragment>
export const Mode = 8; // 对应 <React.StrictMode>
export const ContextConsumer = 9; // 对应 <Context.Consumer>
export const ContextProvider = 10; // 对应 <Context.Provider>
export const ForwardRef = 11; // 对应 React.ForwardRef
export const Profiler = 12; // 对应 <Profiler/ >
export const SuspenseComponent = 13; // 对应 <Suspense>
export const MemoComponent = 14; // 对应 React.memo 返回的组件
可控render中学习到的重要函数:
-
React.Children.toArray用于扁平化、规范化 React.element 的 children 组成的数组。
-
React.Children.forEach用于遍历子节点。值得注意的是:React.Children.forEach 本身就可以把 children 扁平化,
所以React.Children.forEach
=React.Children.toArray+Array.prototype.forEach。 -
React.cloneElement用于以 element 元素为样板克隆并返回新的 React element 元素,返回元素的 props 是将新的 props 与原始元素的 props 浅层合并后的结果。
React.cloneElement的三个参数:
- element(React 元素):要克隆的 React 元素,即要被复制的元素。
- props(对象):要添加或替换到新元素的新属性(props)对象。
- children(React 元素/ React 组件/ 值):作为新元素的子元素传递的内容。
Babel解析JSX:
Babel能够解析JSX并且JSX语法能够实现来源于两个插件,分别是:
- @babel/plugin-syntax-jsx : 使用这个插件,能够让 Babel 有效的解析 JSX 语法。
- @babel/plugin-transform-react-jsx :这个插件内部调用了 @babel/plugin-syntax-jsx,可以把 React JSX 转化成 JS 能够识别的 createElement 格式。
在老版本React中如果需要编写jsx文件那么就得引入React,因为jsx最终会变成React.createElement的形式 ,所以必须引入React防止出现报错。这也就是Classic Runtime。
新版本 React 已经不需要引入 createElement,这是因为plugin-syntax-jsx 已经向文件中提前注入了 _jsxRuntime api。不过这种模式下需要我们在 .babelrc 设置 runtime: automatic 。这也就是Automatic Runtime。
"presets": [
["@babel/preset-react",{
"runtime": "automatic"
}]
],
总结:这就是jsx的初步认识,掌握JSX如何进行转换的,最终转换成了什么,了解Babel对JSX的解析大概流程。