初步认识JSX

194 阅读3分钟

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的三个参数:

    1. element(React 元素):要克隆的 React 元素,即要被复制的元素。
    2. props(对象):要添加或替换到新元素的新属性(props)对象。
    3. 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的解析大概流程。