const element = Hello, world!
;
这段 JSX 代码会被 Babel 等工具转换为:
const element = React.createElement('h1', null, 'Hello, world!');
**为什么要用 JSX**:
* 直观:在 JavaScript 中直接描述 UI 结构
* 强大:可以使用 JavaScript 的全部能力
* 类型安全:编译时就能发现错误
===== 4.2 JSX 语法规则 =====
**必须有一个根元素**:
JSX 表达式必须有一个外层包裹元素。
// 正确
return (
标题
内容
);
// 错误 - 没有根元素
return (
标题
内容
);
// 使用 Fragment 作为根元素
return (
<>
标题
内容
>
);
**使用 className 代替 class**:
class 是 JavaScript 的保留字,所以在 JSX 中使用 className。
// 正确
内容
// 错误
内容
**使用 camelCase 属性名**:
HTML 属性在 JSX 中使用 camelCase。
// HTML
// JSX
**标签必须闭合**:
所有标签都必须正确闭合。
// 正确
// 错误
===== 4.3 在 JSX 中嵌入表达式 =====
使用花括号 {} 在 JSX 中嵌入 JavaScript 表达式。
**变量和表达式**:
const name = 'React';
const element = Hello, {name}!
;
const sum = 1 + 2;
const result = 1 + 2 = {sum}
;
const element = 2 + 2 = {2 + 2}
;
**函数调用**:
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: '张',
lastName: '三'
};
const element = {formatName(user)}
;
**条件渲染**:
const isLoggedIn = true;
// 使用三元运算符
const element = (
{isLoggedIn ? : }
);
// 使用逻辑与运算符
const element = (
{isLoggedIn && }
);
// 使用变量
let content;
if (isLoggedIn) {
content = ;
} else {
content = ;
}
const element = {content};
===== 4.4 JSX 中的属性 =====
**字符串字面量**:
const element = ;
const element =
;
**嵌入表达式**:
const avatarUrl = 'https://example.com/avatar.jpg';
const element =
;
const element = ;
**展开属性**:
const props = {
firstName: '张',
lastName: '三',
age: 25
};
const element = ;
// 等同于
const element = ;
===== 4.5 JSX 防止 XSS 攻击 =====
React DOM 在渲染之前会转义所有嵌入的值。这确保了你永远不会注入未转义的内容。
const title = response.potentiallyMaliciousInput;
// 这是安全的
const element = {title}
;
默认情况下,React DOM 会将所有内容在渲染前进行转义。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(跨站脚本)攻击。
**危险地设置 HTML**:
有时你需要设置 HTML 内容(如富文本编辑器),这时可以使用 dangerouslySetInnerHTML:
function MyComponent() {
const htmlContent = { __html: '粗体文本' };
return ;
}
⚠️ 警告:使用 dangerouslySetInnerHTML 存在安全风险,确保内容是可信的。
===== 4.6 JSX 表示对象 =====
Babel 会将 JSX 编译为 React.createElement() 调用。
这两个例子完全等同:
const element = (
Hello, world!
);
const element = React.createElement(
'h1',
{ className: 'greeting' },
'Hello, world!'
);
React.createElement() 执行后返回一个类似这样的对象:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
这样的对象被称为"React 元素",它描述了你希望在屏幕上看到的内容。React 读取这些对象,用它们来构建 DOM 并保持其更新。
===== 4.7 注释 =====
在 JSX 中使用注释:
const element = (
{/* 这是注释 */}
标题
{/
多行
注释
/}
);
===== 4.8 JSX 的 children =====
**字符串**:
const element = Hello World;
**JSX 元素**:
const element = (
Hello
World
);
**混合类型数组**:
const items = ['苹果', '香蕉', '橙子'];
const element = (
{>items.map((item, index) => (
- {item}
))}
);
**函数作为 children**:
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return {items};
}
function ListOfTenThings() {
return (
{(index) => 这是第 {index} 项}
);
}
===== 4.9 布尔值、Null 和 Undefined =====
false、null、undefined 和 true 都是有效的 children,但它们不会被渲染。
// 以下都会渲染相同的结果
{false}
{null}
{undefined}
{true}
这在条件渲染中很有用:
{showHeader && }
**注意**:数字 0 会被渲染出来,要注意这种情况:
// 如果 items.length 为 0,会显示 0
{items.length && }
// 正确做法
{items.length > 0 && }
===== 4.10 Fragment =====
Fragment 允许你将子元素列表分组,而无需向 DOM 添加额外节点。
import React from 'react';
function Example() {
return (
);
}
// 短语法
function Example() {
return (
<>
>
);
}
带 key 的 Fragment:
function Glossary(props) {
return (
{props.items.map(item => (
- {item.term}
- {item.description}
))}
);
}
===== 4.11 总结 =====
本章深入讲解了 JSX 的各个方面:
* JSX 的基本语法规则
* 嵌入表达式
* 属性设置
* XSS 防护
* children 的处理
* Fragment 的使用
掌握 JSX 是 React 开发的基础。下一章我们将学习组件的概念和用法。