JSX 本质是什么?为什么 React 17 以后不用再手动 import React?
先理解原理和示例,再练习完整口述与追问。
回答要点
JSX 是语法扩展,编译后成为创建 React 元素的函数调用:旧转换为 React.createElement(type, props, ...children),React 17 起的新转换为 jsx()/jsxs(),由编译器自动从 react/jsx-runtime 导入,因此不再需要手动引入 React。React 元素是描述 UI 的普通对象。
原理拆解
Babel 或 TypeScript、SWC、esbuild 遇到 <Button type="primary">保存</Button> 时,小写标签名编译为字符串(原生元素),大写编译为变量引用(组件),所以组件名必须大写。属性中的 key 会被单独提取,ref 在 React 19 起作为普通 prop 传给函数组件。
新转换的 jsx(type, props, key) 把 children 放进 props,静态多子节点用 jsxs,开发环境使用 jsxDEV 并附带源码位置。生成的元素对象包含 $$typeof: Symbol.for('react.transitional.element')(React 19,之前为 react.element)、type、key、props;Symbol 类型的 $$typeof 不能被 JSON 表达,可防止服务端返回的 JSON 被伪造成元素。
示例与推演
import { jsx as _jsx, jsxs as _jsxs } from 'react/jsx-runtime'
const element = _jsxs('ul', {
className: 'list',
children: [_jsx('li', { children: 'A' }, 'a'), _jsx('li', { children: 'B' }, 'b')]
})
这是 <ul className="list"><li key="a">A</li><li key="b">B</li></ul> 的大致编译结果。
易错点
JSX 中的 {} 只能放表达式,不能写 if 语句;渲染 0 && <List /> 会把 0 显示出来。Vue 也能用 JSX,但会编译为 Vue 的 h 函数,配置不同的转换插件。
参考回答可直接练习口述
JSX 是语法糖,编译后变成创建 React 元素的函数调用,元素只是描述 UI 的普通对象,包含 type、props、key。React 17 之前编译为 React.createElement,所以每个文件都要引入 React;17 之后的新转换调用 jsx-runtime 里的 jsx 函数,由编译器自动导入,就不用手写 import 了。小写标签编译成字符串,大写编译成组件引用,所以组件名必须大写。