实现JSX的转换( 二 )


转换结果如下:
const element = React.createElement("div",{ className: "container" },"Hello, world!");从React 17开始,引入了新的JSX转换功能,称为"Runtime Automatic"(自动运行时) 。这意味着在使用JSX语法时,不再需要手动引入React库 。在自动运行时模式下,JSX会被转换成新的入口函数,import {jsx as _jsx} from 'react/jsx-runtime'; 和 import {jsxs as _jsxs} from 'react/jsx-runtime'; 。
转换结果如下:
import { jsx as _jsx } from "react/jsx-runtime";const element = _jsx("div", {className: "container",children: "Hello, world!" });接下来我们就来实现jsx方法或React.createElement方法(包括dev、prod两个环境) 。
工作量包括:

  • 实现jsx方法
  • 实现打包流程
  • 实现调试打包结果的环境
实现 jsx 转换方法jsx 转换方法包括:
  • React.createElement方法
  • jsxDEV方法(dev环境)
  • jsx方法(prod环境)
实现React.createElement在React 17之前,JSX转换应用的是createElement方法,下面是它的实现:
/** ** @param type 元素类型 * @param config 元素属性,包括key,不包括子元素children * @param maybeChildren 子元素children * @returns 返回一个ReactElement */const createElement = (type: ElementType,config: any,...maybeChildren: any) => {// reactElement 自身的属性let key: Key = null;let ref: Ref = null;// 创建一个空对象props,用于存储属性const props: Props = {};// 遍历config对象,将ref、key这些ReactElement内部使用的属性提取出来,不应该被传递下去for (const prop in config) {const val = config[prop];if (prop === 'key') {if (val !== undefined) {key = '' + val;}continue;}if (prop === 'ref') {if (val !== undefined) {ref = val;}continue;}// 去除config原型链上的属性,只要自身// 一般使用{...props}将所有属性都传递下去,所以摘除ref、key属性外需要被保存到props中if ({}.hasOwnProperty.call(config, prop)) {props[prop] = val;}}const maybeChildrenLength = maybeChildren.length;if (maybeChildrenLength) {// [child] [child, child, child]if (maybeChildrenLength === 1) {props.children = maybeChildren[0];} else {props.children = maybeChildren;}}return ReactElement(type, key, ref, props);};注意:React.createElement方法和jsx方法的区别这里只体现在第三个参数上 。
实现jsx方法从React 17之后,JSX转换应用的是jsx方法,下面是它的实现:
/** ** @param type 元素类型 * @param config 元素属性 * @param maybeKey 可能的key值 * @returns 返回一个ReactElement */const jsx = (type: ElementType, config: any, maybeKey: any) => {// 初始化key和ref为空let key = null;let ref = null;// 创建一个空对象props,用于存储属性const props: Props = {};// 遍历config对象,将ref、key这些ReactElement内部使用的属性提取出来,不应该被传递下去for (const prop in config) {const val = config[prop];if (prop === "key") {continue;}if (prop === "ref") {if (val !== undefined) {ref = val;}continue;}// 一般使用{...props}将所有属性都传递下去,所以摘除ref、key属性外需要被保存到props中if ({}.hasOwnProperty.call(config, prop)) {props[prop] = val;}}// 将 maybeKey 添加到 key 中if (maybeKey !== undefined) {key = "" + maybeKey;}return ReactElement(type, key, ref, props);};这段代码定义了一个jsx函数,主要用于创建React元素 。首先,它会提取可能存在的key和ref属性,并将剩余属性添加到一个新的props对象中 。最后用ReactElement函数创建一个React元素并返回 。
从上面代码中可以看到还实现了ReactElement方法:
// jsx-runtime.jsconst supportSymbol = typeof Symbol === 'function' && Symbol.for;// 为了不滥用 React.elemen,所以为它创建一个单独的键// 为React.element元素创建一个 symbol 并放入到 symbol 注册表中export const REACT_ELEMENT_TYPE = supportSymbol? Symbol.for('react.element'): 0xeac7;export const ReactElement = function (type, key, ref, props) {const element = {$$typeof: REACT_ELEMENT_TYPE,type,key,ref,props,_mark: 'lsh',};return element;};export const jsx =...用自己实现的的jsx接入Demo我们试着把自己实现的jsx方法,创建一个ReactElement,看它是否能够渲染在页面上 。
实现JSX的转换

文章插图
实现jsx方法
jsx-Demo运行地址
jsx方法和createElement的区别jsx函数和createElement函数都用于在React中创建虚拟DOM元素,但它们的语法和用法有所不同 。jsx函数来自于React 17及更高版本中的新的JSX转换功能,称为"Runtime Automatic" 。


推荐阅读