React的JSX语法是不能直接运行的宿主环境的,需要将 JSX 代码转换为 js 代码才能在宿主环境运行。
转换后的代码就是在源码中实现的 React.createElement 方法,jsx 方法等价于 React.createElement 方法。至于转换过程,交给 babel 去处理
React17之前的转换
import React from 'react';
function App() {
return <h1>Hello World</h1>;
}
转换后
import React from 'react';
function App() {
return React.createElement('h1', null, 'Hello world');
}
React17之后的转换
React17 与 Babel 的合作,使新的 JSX 转换可以让我们不引入 React 既可使用 JSX 了。
因为在编译时,就自动从 react/jsx-runtime 中
引入了 jsx 方法,import {jsx as _jsx} from 'react/jsx-runtime'。相比之前的全量引入,可以一定程度上减少包的提及大小
具体可以查看官方博客 介绍全新的 JSX 转换
输入
import React from 'react';
function App() {
return <h1>Hello World</h1>;
}
输出
// 由编译器引入(禁止自己引入!)
import {jsx as _jsx} from 'react/jsx-runtime';
function App() {
return _jsx('h1', { children: 'Hello world' });
}
可在 babel 官网 babeljs.io/repl# 尝试
React.createElement 方法的实现
要创建一个 React 元素,就需要调用 React.createElement 方法,回顾一下我们平时开发中,React 元素包含哪些属性
-
构造一个
ReactElement元素,返回ReactElementTypeconst ReactElement = ( type: Type, key: Key, ref: Ref, props: Props ): ReactElementType => { return { /** * 识别是否为 ReactElement * 为了防止这个值被滥用,将其值定义为全局唯一的 Symbol 类型的值 * */ "@@typeof": REACT_ELEMENT_TYPE, type, key, ref, props }; }; -
React 上的
createElement方法就对应的是jsx/jsxDEV方法,不过要区分环境。开发环境下,createElement对应的是jsxDEV,生产环境对应的的jsx
// 打包后:react/jsx-dev-runtime
// export const jsxDEV = ...
// 打包后:react/jsx-runtime
export const jsx = (
type: ElementType,
config: any,
...maybeChildren: any[]
) => {
let key: Key = null;
let ref: Ref = null;
const props: Props = {};
// 处理 props 上除了 children 的属性
for (const prop in config) {
const val = config[prop];
// key 和 ref 不放到 props 上
if (prop === "key") {
if (val !== undefined) {
key = "" + val;
}
continue;
}
if (prop === "ref") {
if (val !== undefined) {
ref = val;
}
continue;
}
// 如果是它自己的prop,就给它赋值。避免赋值给原型上的属性
if ({}.hasOwnProperty.call(config, prop)) {
props[prop] = val;
}
}
// 处理children
const maybeChildrenLength = maybeChildren.length;
if (maybeChildrenLength) {
// 如果只有一个children,则将数组解开,直接将children赋值给props.children
if (maybeChildrenLength === 1) {
props.chidren = maybeChildren[0];
} else {
props.chidren = maybeChildren;
}
}
return ReactElement(type, key, ref, props);
};
jsxDEV 函数会生成带有调试信息的 React 元素,用于在开发模式下生成 JSX 元素的辅助函数。
而 jsx 方法是 Babel 或其他 JSX 转换工具生成的函数,用于将 JSX 代码转换为普通的 JavaScript 代码, 用于编译后的环境