JSX 的使用


前言

JSX 一种 JavaScript 的语法扩展,它类似于模板语言,但具有 JavaScript 的全部功能。JSX 可以生成 React 元素,也可以生成其他任何类型的值。Writing Markup with JSX – React

New JSX Transform

React v17.0 – React Blog, 中引入了 New JSX Transform, Introducing the New JSX Transform – React Blog.

在 React 17 之前, JSX 都是编译成 React.createElement 方法,所以代码中,必需引入 react.但在 React 17 之后,JSX 会被编译成 _jsx 方法, 引入的组件不需要自行添加,是编译器添加的, 这样就可以灵活决定用什么 jsx ,可以是 react/jsx-runtime 也可以是 @emotion/react

// Inserted by a compiler (don't import it yourself!)
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

新的 JSX Transform 的好处:

  • With the new transform, you can use JSX without importing React.
  • Depending on your setup, its compiled output may slightly improve the bundle size.
  • It will enable future improvements that reduce the number of concepts you need to learn React.

JSX Pragma

对于有些框架, 比如 CRA 是无法修改编译器的配置,所以需要通过 JSX Pragma 来指定编译器。

编译工具

JSX 的最大好处就是开发的时候,我们可以写类似组件的形式代码,在编译后, 转换为对应的函数,生成 DOM.

编译 JSX 通常是 babel, swc, esbuild 这类工具处理。我们需要关注的是设置 rumtimeimportSource 两个参数。

  • runtime: classic | automatic: 默认 classic, 建议修改成 automatic 来使用 New JSX Transform
  • importSource: string: 指定 jsx 从什么模块导入, 默认是 react.

babel

@babel/plugin-transform-react-jsx · Babel, 默认 runtime 为 classic

SWC

Compilation – SWC

比如我们使用 vite 的 vitejs/vite-plugin-react-swc: Speed up your Vite dev server with SWC,就会有对应的配置, runtime 默认为 automatic, jsxImportSource 默认为 react.

esbuild

esbuild - Content Types

比如 vite 的生成环境构建使用的就是 esbuild.

读取的 tsconfig.json 的配置: esbuild - Content Types,

Only certain tsconfig.json fields are respected

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxFactory": "React.createElement"
  }
}

TS 设置

为了编译器能够正确的处理 JSX,我们需要设置 jsxjsxImportSource 两个参数。特别是一些项目,如果直接用 tsc 编译的话。

jsx 配置

TypeScript: TSConfig Reference - Docs on every TSConfig option TypeScript: Documentation - JSX

TypeScript 提供了三种 JSX 模式:

  • preserve: 组件代码不做编译,后置可能有其他工具处理,输出文件为 .jsx
  • react: 将 JSX 转换为 React.createElement,输出文件为 .js
  • react-jsx: 使用 New JSX Transform,输出文件为 .js
  • react-jsxdev: 调用 jsxDev, 输出 .js

jsxImportSource 配置

TypeScript: TSConfig Reference - Docs on every TSConfig option

配置这个,可以指定 JSX 的函数,从什么包导入。

如何 JSX 支持其他框架

比如使用 preact 的 h 方法, 那么我们需要关注的是:

  • jsxFactory
  • jsxFragmentFactory

比如 tsconfig 配置:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment"
  }
}

使用的效果:

import { h, Fragment } from "preact";
const HelloWorld = () => (
  <>
    <div>Hello</div>
  </>
);

将会编译成:

const preact_1 = require("preact");
const HelloWorld = () => ((0, preact_1.h)(preact_1.Fragment, null,
    (0, preact_1.h)("div", null, "Hello")));

技术总结

  • 使用 React 17+ 版本。
  • JSX 设置 runtimeautomaticimportSource 按需设置。
  • TS 中也要配置 jsxjsxImportSource 两个参数。