JSX 是 React 中用来描述 UI 的语法扩展,看起来像 HTML,但它不是 HTML,也不是模板字符串,而是 JavaScript 的语法糖。浏览器不能直接识别 JSX,需要 Babel、TypeScript、SWC 等工具编译。

1. 基本样子

const name = "Alice";

const element = (
  <h1 className="title">
    Hello, {name}
  </h1>
);

其中:

  • className 对应 HTML 的 class
  • {} 里可以写 JavaScript 表达式
  • JSX 本身是一个表达式,可以赋值、传参、返回

2. 编译后是什么

传统 JSX transform 会把它编译成:

const element = React.createElement(
  "h1",
  { className: "title" },
  "Hello, ",
  name
);

React 17 之后的新 JSX transform 会自动引入运行时:

import { jsx as _jsx } from "react/jsx-runtime";

const element = _jsx("h1", {
  className: "title",
  children: ["Hello, ", name]
});

所以现代 React 项目里,很多时候不写 import React 也能用 JSX。

3. 本质

JSX 的本质是 React.createElement / jsx 调用的语法糖,用来创建 React Element。

它编译后返回的不是 DOM 节点,也不是组件实例,而是一个普通的 JavaScript 对象,大概长这样:

{
  type: "h1",
  props: {
    className: "title",
    children: ["Hello, ", name]
  },
  key: null,
  ref: null,
  $$typeof: Symbol(react.element)
}

这个对象叫 React Element,它只是对 UI 的描述。React 后续会根据这棵 Element 树进行协调,最终生成或更新真实 DOM。

4. 几个关键点

  • <div /> 编译后 type 是字符串 "div"
  • <MyComponent /> 编译后 type 是函数或类组件本身
  • <></> 是 React.Fragment 的语法糖
  • {} 里只能放表达式,不能直接放 if、for 语句
  • 属性通常是 camelCase,如 onClick、className
  • style 接收对象:style={{ color: "red" }}
  • key 是 React 的特殊属性,用于列表协调

5. JSX总结

JSX 不是 HTML,也不是模板引擎。
它是 JavaScript 的语法扩展,编译后变成创建 React Element 的函数调用。
React Element 是描述 UI 的普通对象,React 再根据它进行协调和渲染。
所以 JSX 的本质就是:声明式 UI 语法 + React Element 工厂调用的语法糖。

出现<>, 会自动创建元素

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="example"></div>

    <!-- React 16.14.0 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <!-- ReactDOM 16.14.0 -->
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <!-- Babel转换器 (替代browser.min.js) -->
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>
    <script type="text/babel">
      //在JSX中, 出现<>, 会自动创建元素
      ReactDOM.render(
        <h1>Hello React!</h1>,
        document.getElementById("example")
      );
    </script>
  </body>
</html>

出现{}, 认为是变量

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="example"></div>

    <!-- React 16.14.0 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <!-- ReactDOM 16.14.0 -->
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <!-- Babel转换器 (替代browser.min.js) -->
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>
    <script type="text/babel">
      //在JSX中, 出现{}, 认为是变量
      var text = "学姐";
      ReactDOM.render(
        <h1>哈喽, {text}!</h1>,
        document.getElementById("example")
      );
    </script>
  </body>
</html>

如何写html标签属性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <style type="text/css">
      .bg {
        background: yellow;
      }
    </style>
  </head>
  <body>
    <div id="example"></div>

    <!-- React 16.14.0 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <!-- ReactDOM 16.14.0 -->
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <!-- Babel转换器 (替代browser.min.js) -->
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>
    <script type="text/babel">
      //1.在渲染的元素内容中, 不能出现for, class, 因为和React中的关键词重名
      //for 写成 htmlFor
      //class 写成 className
      //2.渲染的元素内容, 只能有一个根节点
      //3.单标签需要用/闭合
      ReactDOM.render(
        <div className="bg">
          <label htmlFor="username">用户名:</label>
          <input type="text" id="username" />
        </div>,
        document.getElementById("example")
      );
    </script>
  </body>
</html>

循环渲染

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="example"></div>

    <!-- React 16.14.0 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <!-- ReactDOM 16.14.0 -->
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <!-- Babel转换器 (替代browser.min.js) -->
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>
    <script type="text/babel">
      var arr = ["宝宝", "蓉蓉", "经纪人", "楼上邻居", "隔壁老王"];

      ReactDOM.render(
        <ul>
          <li>{arr[0]}</li>
          <li>{arr[1]}</li>
          <li>{arr[2]}</li>
          <li>{arr[3]}</li>
        </ul>,
        document.getElementById("example")
      );

      //循环操作
      ReactDOM.render(
        <ul>
          {arr.map(function (e) {
            return <li>Hi, {e}!</li>;
          })}
        </ul>,
        document.getElementById("example")
      );
    </script>
  </body>
</html>

写表达式(变量,运算,函数调用)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="example"></div>

    <!-- React 16.14.0 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <!-- ReactDOM 16.14.0 -->
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <!-- Babel转换器 (替代browser.min.js) -->
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>
    <script type="text/babel">
      //注: JSX中的{}中, 可以写表达式(变量,运算,函数调用)
      ReactDOM.render(
        <div>1 + 1 = {1 + 1}</div>,
        document.getElementById("example")
      );
    </script>
  </body>
</html>

数组存放html元素可直接渲染

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="example"></div>

    <!-- React 16.14.0 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <!-- ReactDOM 16.14.0 -->
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <!-- Babel转换器 (替代browser.min.js) -->
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>
    <script type="text/babel">
      //数组中存放元素
      var arr1 = [
        <h1>Hello world!</h1>,
        <h2>你好, 世界!</h2>,
        <h3>莎娃迪卡!</h3>,
      ];

      //当数组中存放的是元素, 可以直接使用数组进行渲染, 相当于把数组的每个元素进行渲染
      ReactDOM.render(<div>{arr1}</div>, document.getElementById("example"));
    </script>
  </body>
</html>