第四章:JSX 详解

JSX(JavaScript XML)是 React 中用于描述 UI 的语法扩展。它看起来像是 HTML,但实际上是 JavaScript。

const element = <h1>Hello, world!</h1>;

这段 JSX 代码会被 Babel 等工具转换为:

const element = React.createElement('h1', null, 'Hello, world!');

为什么要用 JSX

  • 直观:在 JavaScript 中直接描述 UI 结构
  • 强大:可以使用 JavaScript 的全部能力
  • 类型安全:编译时就能发现错误

必须有一个根元素

JSX 表达式必须有一个外层包裹元素。

// 正确
return (
  <div>
    <h1>标题</h1>
    <p>内容</p>
  </div>
);
 
// 错误 - 没有根元素
return (
  <h1>标题</h1>
  <p>内容</p>
);
 
// 使用 Fragment 作为根元素
return (
  <>
    <h1>标题</h1>
    <p>内容</p>
  </>
);

使用 className 代替 class

class 是 JavaScript 的保留字,所以在 JSX 中使用 className。

// 正确
<div className="container">内容</div>
 
// 错误
<div class="container">内容</div>

使用 camelCase 属性名

HTML 属性在 JSX 中使用 camelCase。

// HTML
<input readonly tabindex="0" />
 
// JSX
<input readOnly tabIndex={0} />

标签必须闭合

所有标签都必须正确闭合。

// 正确
<img src="photo.jpg" alt="照片" />
<input type="text" />
 
// 错误
<img src="photo.jpg" alt="照片">
<input type="text">

使用花括号 {} 在 JSX 中嵌入 JavaScript 表达式。

变量和表达式

const name = 'React';
const element = <h1>Hello, {name}!</h1>;
 
const sum = 1 + 2;
const result = <p>1 + 2 = {sum}</p>;
 
const element = <h1>2 + 2 = {2 + 2}</h1>;

函数调用

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}
 
const user = {
  firstName: '张',
  lastName: '三'
};
 
const element = <h1>{formatName(user)}</h1>;

条件渲染

const isLoggedIn = true;
 
// 使用三元运算符
const element = (
  <div>
    {isLoggedIn ? <UserGreeting /> : <GuestGreeting />}
  </div>
);
 
// 使用逻辑与运算符
const element = (
  <div>
    {isLoggedIn && <UserGreeting />}
  </div>
);
 
// 使用变量
let content;
if (isLoggedIn) {
  content = <UserGreeting />;
} else {
  content = <GuestGreeting />;
}
const element = <div>{content}</div>;

字符串字面量

const element = <div tabIndex="0"></div>;
const element = <img src="photo.jpg" />;

嵌入表达式

const avatarUrl = 'https://example.com/avatar.jpg';
const element = <img src={avatarUrl} />;
 
const element = <div tabIndex={0}></div>;

展开属性

const props = {
  firstName: '张',
  lastName: '三',
  age: 25
};
 
const element = <User {...props} />;
// 等同于
const element = <User firstName="张" lastName="三" age={25} />;

React DOM 在渲染之前会转义所有嵌入的值。这确保了你永远不会注入未转义的内容。

const title = response.potentiallyMaliciousInput;
// 这是安全的
const element = <h1>{title}</h1>;

默认情况下,React DOM 会将所有内容在渲染前进行转义。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(跨站脚本)攻击。

危险地设置 HTML

有时你需要设置 HTML 内容(如富文本编辑器),这时可以使用 dangerouslySetInnerHTML:

function MyComponent() {
  const htmlContent = { __html: '<b>粗体文本</b>' };
  return <div dangerouslySetInnerHTML={htmlContent} />;
}

⚠️ 警告:使用 dangerouslySetInnerHTML 存在安全风险,确保内容是可信的。

Babel 会将 JSX 编译为 React.createElement() 调用。

这两个例子完全等同:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
 
const element = React.createElement(
  'h1',
  { className: 'greeting' },
  'Hello, world!'
);

React.createElement() 执行后返回一个类似这样的对象:

const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

这样的对象被称为“React 元素”,它描述了你希望在屏幕上看到的内容。React 读取这些对象,用它们来构建 DOM 并保持其更新。

在 JSX 中使用注释:

const element = (
  <div>
    {/* 这是注释 */}
    <h1>标题</h1>
    {/
      多行
      注释
    /}
  </div>
);

字符串

const element = <div>Hello World</div>;

JSX 元素

const element = (
  <div>
    <span>Hello</span>
    <span>World</span>
  </div>
);

混合类型数组

const items = ['苹果', '香蕉', '橙子'];
const element = (
  <ul>
    {>items.map((item, index) => (
      <li key={index}>{item}</li>
    ))}
  </ul>
);

函数作为 children

function Repeat(props) {
  let items = [];
  for (let i = 0; i < props.numTimes; i++) {
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}
 
function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>这是第 {index}</div>}
    </Repeat>
  );
}

false、null、undefined 和 true 都是有效的 children,但它们不会被渲染。

// 以下都会渲染相同的结果
<div />
 
<div></div>
 
<div>{false}</div>
 
<div>{null}</div>
 
<div>{undefined}</div>
 
<div>{true}</div>

这在条件渲染中很有用:

<div>
  {showHeader && <Header />}
</div>

注意:数字 0 会被渲染出来,要注意这种情况:

// 如果 items.length 为 0,会显示 0
<div>{items.length && <MessageList items={items} />}</div>
 
// 正确做法
<div>{items.length > 0 && <MessageList items={items} />}</div>

Fragment 允许你将子元素列表分组,而无需向 DOM 添加额外节点。

import React from 'react';
 
function Example() {
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  );
}
 
// 短语法
function Example() {
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  );
}

带 key 的 Fragment:

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}

本章深入讲解了 JSX 的各个方面:

  • JSX 的基本语法规则
  • 嵌入表达式
  • 属性设置
  • XSS 防护
  • children 的处理
  • Fragment 的使用

掌握 JSX 是 React 开发的基础。下一章我们将学习组件的概念和用法。

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • react/jsx.txt
  • 最后更改: 2026/03/13 15:50
  • 张叶安