什么是jsx
JSX 是 JavaScript XML 的缩写,它允许我们在 JavaScript 代码中直接编写类似 HTML 的语法,从而更直观地描述 UI 结构。
react 中的 jsx
在 React 中,JSX 语法会被编译成 React.createElement 或 jsx 函数调用。这个编译过程通常是通过 Babel 等工具实现的。这种编译结果生成了一个描述 UI 结构的对象,而 React 使用这些对象来构建和更新 DOM。
const element = <h1>Hello, world!</h1>;
// 编译后结果
const element = /*#__PURE__*/ React.createElement('h1', null, 'Hello, world!');
// 或
import { jsx as _jsx } from 'react/jsx-runtime';
const element = /*#__PURE__*/ _jsx('h1', {
children: 'Hello, world!'
});
jsx 两个部分
编译时: 编译时由babel实现 运行时: 实现 jsx 或 React.createElement 两个方法, 但最终的效果是相同的:创建一个描述 UI 的对象(React 元素)两个方法返回类下面的数据结构描述 UI。
const REACT_ELEMENT_TYPE = Symbol.for('react.element');
function ReactElement(type, key, ref, props) {
const element = {
// 特殊的标识符,用于标识这是一个 React 元素
$$typeof: REACT_ELEMENT_TYPE,
// 元素的类型,可以是字符串(HTML 标签)或函数(React 组件)
type,
// 元素的唯一标识符(可选),用于优化 React 的调和过程
key,
// 引用,通常用于访问或操作 DOM 元素(可选)
ref,
// 元素的属性
props,
// 自定义字段 实现时与 真实的ReactElement 区分
_owner: '_Yzj' // 这里的 '_Yzj' 只是一个示例,占位符,实际中是 Fiber 节点
};
return element;
}
实现 JSX 方法
- React.createElement 方法
const RESERVED_PROPS = {
key: true,
ref: true,
};
function createElement(type, config, ...children) {
const props = {};
let key = null;
let ref = null;
if (config != null) {
if (config.ref !== undefined) {
ref = config.ref;
}
if (config.key !== undefined) {
key = '' + config.key;
}
for (const propName in config) {
if (Object.prototype.hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
}
if (children.length === 1) {
props.children = children[0];
} else if (children.length > 1) {
props.children = children;
}
return ReactElement(type, key, ref, props);
}
- jsx 方法
React 17 引入了新的 JSX 转换方式,不再需要显式导入 React。新的转换方式使用两个新的自动导入函数:jsx 和 jsxs。jsx 用于创建没有子元素或只有一个子元素的元素,而 jsxs 用于创建有多个子元素的元素
const element = <h1>Hello, world! <span>1233</span></h1>;
// 转化后的结果
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const element = /*#__PURE__*/_jsxs("h1", {
children: ["Hello, world! ", /*#__PURE__*/_jsx("span", {
children: "1233"
})]
});
-
jsx
function jsx( type: string | Function, config: Props, maybeKey?: Key ): ReactElement { const props: Props = {}; let key: Key = null; let ref: Ref = null; if (maybeKey !== undefined) { key = '' + maybeKey; } if (config != null) { if (config.ref !== undefined) { ref = config.ref; } if (config.key !== undefined) { key = '' + config.key; } for (const propName in config) { if ( Object.prototype.hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; } } } return ReactElement(type, key, ref, props); } -
jsxs
function jsxs( type: string | Function, config: Props, maybeKey?: Key ): ReactElement { const props: Props = {}; let key: Key = null; let ref: Ref = null; if (maybeKey !== undefined) { key = '' + maybeKey; } if (config != null) { if (config.ref !== undefined) { ref = config.ref; } if (config.key !== undefined) { key = '' + config.key; } for (const propName in config) { if ( Object.prototype.hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; } } } const childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = arguments[2]; } else if (childrenLength > 1) { const childArray = Array(childrenLength); for (let i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } props.children = childArray; } return ReactElement(type, key, ref, props); }