React JSX 语法详解
概述
JSX (JavaScript XML) 是 React 的核心特性之一,它是 JavaScript 的语法扩展,允许我们在 JavaScript 代码中编写类似 HTML 的标记。JSX 使得组件的结构更加直观和易于理解。
🎯 什么是 JSX?
JSX 基本概念
jsx
// JSX 示例
const element = <h1>Hello, React!</h1>;
// 这不是字符串,也不是 HTML
// 这是 JSX - JavaScript 的语法扩展JSX 的本质
jsx
// JSX 代码
const element = <h1 className="greeting">Hello, world!</h1>;
// 编译后的 JavaScript 代码
const element = React.createElement(
'h1',
{ className: 'greeting' },
'Hello, world!'
);
// 最终生成的对象
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};📝 JSX 基础语法
1. 嵌入表达式
在 JSX 中使用大括号 {} 嵌入 JavaScript 表达式:
jsx
function Greeting() {
const name = '张三';
const age = 25;
return (
<div>
{/* 嵌入变量 */}
<h1>你好,{name}!</h1>
{/* 嵌入表达式 */}
<p>明年你将 {age + 1} 岁</p>
{/* 嵌入函数调用 */}
<p>当前时间:{new Date().toLocaleTimeString()}</p>
{/* 嵌入三元表达式 */}
<p>{age >= 18 ? '成年人' : '未成年人'}</p>
</div>
);
}2. JSX 属性
jsx
function ImageCard() {
const imageUrl = 'https://example.com/image.jpg';
const altText = '示例图片';
const isActive = true;
return (
<div>
{/* 字符串属性 */}
<img src="logo.png" alt="Logo" />
{/* 动态属性 */}
<img src={imageUrl} alt={altText} />
{/* 布尔属性 */}
<button disabled={!isActive}>点击</button>
{/* className 代替 class */}
<div className="container">内容</div>
{/* 驼峰命名 */}
<label htmlFor="username">用户名</label>
<input id="username" tabIndex="1" />
</div>
);
}3. 子元素
jsx
function Layout() {
return (
<div className="layout">
{/* 单个子元素 */}
<header>
<h1>网站标题</h1>
</header>
{/* 多个子元素 */}
<main>
<article>文章内容</article>
<aside>侧边栏</aside>
</main>
{/* 嵌套子元素 */}
<footer>
<div>
<p>版权信息</p>
<p>联系方式</p>
</div>
</footer>
</div>
);
}🔧 JSX 高级用法
1. 条件渲染
jsx
function UserGreeting({ isLoggedIn, username }) {
return (
<div>
{/* 使用 && 运算符 */}
{isLoggedIn && <p>欢迎回来,{username}!</p>}
{/* 使用三元表达式 */}
{isLoggedIn ? (
<button>退出登录</button>
) : (
<button>登录</button>
)}
{/* 使用立即执行函数 */}
{(() => {
if (isLoggedIn) {
return <p>已登录</p>;
} else {
return <p>未登录</p>;
}
})()}
</div>
);
}2. 列表渲染
jsx
function TodoList() {
const todos = [
{ id: 1, text: '学习 React', completed: false },
{ id: 2, text: '编写代码', completed: true },
{ id: 3, text: '测试应用', completed: false }
];
return (
<ul>
{todos.map(todo => (
<li
key={todo.id}
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
>
{todo.text}
</li>
))}
</ul>
);
}3. 片段 (Fragments)
jsx
function Table() {
return (
<table>
<tbody>
{/* 使用 Fragment 避免额外的 DOM 节点 */}
<React.Fragment>
<tr><td>行 1</td></tr>
<tr><td>行 2</td></tr>
</React.Fragment>
{/* 简写语法 */}
<>
<tr><td>行 3</td></tr>
<tr><td>行 4</td></tr>
</>
</tbody>
</table>
);
}4. 样式处理
jsx
function StyledComponent() {
// 内联样式对象
const containerStyle = {
backgroundColor: '#f0f0f0',
padding: '20px',
borderRadius: '8px'
};
const isImportant = true;
return (
<div>
{/* 内联样式 */}
<div style={containerStyle}>
<h2 style={{ color: 'blue', fontSize: '24px' }}>标题</h2>
</div>
{/* 动态 className */}
<p className={`text ${isImportant ? 'important' : ''}`}>
内容
</p>
{/* 使用模板字符串 */}
<div className={`card ${isImportant && 'highlight'}`}>
卡片内容
</div>
</div>
);
}🎨 JSX 中的特殊情况
1. 注释
jsx
function CommentExample() {
return (
<div>
{/* 这是 JSX 中的注释 */}
{/*
多行注释
可以这样写
*/}
<h1>标题</h1>
{
// 单行注释也可以
// 但需要在大括号内
}
</div>
);
}2. 自闭合标签
jsx
function SelfClosingTags() {
return (
<div>
{/* HTML 中的自闭合标签在 JSX 中必须闭合 */}
<img src="image.jpg" alt="图片" />
<input type="text" />
<br />
<hr />
{/* 自定义组件也可以自闭合 */}
<CustomComponent />
</div>
);
}3. 保留字处理
jsx
function ReservedWords() {
return (
<div>
{/* class -> className */}
<div className="container"></div>
{/* for -> htmlFor */}
<label htmlFor="input">标签</label>
<input id="input" />
{/* 其他驼峰命名 */}
<div tabIndex="0" onClick={() => {}}></div>
</div>
);
}🔒 JSX 安全性
防止 XSS 攻击
jsx
function SafeComponent() {
// 用户输入的内容
const userInput = '<script>alert("XSS")</script>';
return (
<div>
{/* React 会自动转义,防止 XSS */}
<p>{userInput}</p>
{/* 显示为:<script>alert("XSS")</script> */}
{/* 如果确实需要渲染 HTML(不推荐) */}
<div dangerouslySetInnerHTML={{ __html: userInput }} />
{/* 这会执行脚本,非常危险! */}
</div>
);
}📋 JSX 最佳实践
1. 保持 JSX 简洁
jsx
// ❌ 不好的做法
function BadExample() {
return (
<div>
{users.filter(u => u.active).map(u => (
<div key={u.id}>
{u.name} - {u.email} - {u.age > 18 ? '成年' : '未成年'}
</div>
))}
</div>
);
}
// ✅ 好的做法
function GoodExample() {
const activeUsers = users.filter(u => u.active);
return (
<div>
{activeUsers.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}
function UserCard({ user }) {
const ageStatus = user.age > 18 ? '成年' : '未成年';
return (
<div>
{user.name} - {user.email} - {ageStatus}
</div>
);
}2. 合理使用条件渲染
jsx
function ConditionalExample({ isLoading, error, data }) {
// ✅ 提前返回
if (isLoading) {
return <LoadingSpinner />;
}
if (error) {
return <ErrorMessage error={error} />;
}
if (!data) {
return <EmptyState />;
}
return <DataDisplay data={data} />;
}3. 使用 key 属性
jsx
function ListExample() {
const items = [
{ id: 1, name: '项目 1' },
{ id: 2, name: '项目 2' },
{ id: 3, name: '项目 3' }
];
return (
<ul>
{/* ✅ 使用唯一的 id 作为 key */}
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
{/* ❌ 避免使用索引作为 key(除非列表是静态的) */}
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}
</ul>
);
}🎯 实战示例
完整的表单组件
jsx
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
setIsSubmitting(true);
// 表单验证和提交逻辑
setTimeout(() => {
setIsSubmitting(false);
alert('表单已提交!');
}, 1000);
};
return (
<form onSubmit={handleSubmit} className="contact-form">
<div className="form-group">
<label htmlFor="name">姓名</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
/>
{errors.name && (
<span className="error">{errors.name}</span>
)}
</div>
<div className="form-group">
<label htmlFor="email">邮箱</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
{errors.email && (
<span className="error">{errors.email}</span>
)}
</div>
<div className="form-group">
<label htmlFor="message">留言</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
rows="4"
required
/>
{errors.message && (
<span className="error">{errors.message}</span>
)}
</div>
<button
type="submit"
disabled={isSubmitting}
className={isSubmitting ? 'submitting' : ''}
>
{isSubmitting ? '提交中...' : '提交'}
</button>
</form>
);
}📝 本章小结
JSX 是 React 开发的核心,它让我们能够以声明式的方式描述 UI。掌握 JSX 语法是学习 React 的重要一步。
关键要点
- ✅ JSX 是 JavaScript 的语法扩展,不是模板语言
- ✅ 使用
{}嵌入 JavaScript 表达式 - ✅ JSX 属性使用驼峰命名法
- ✅ React 自动转义内容,防止 XSS 攻击
- ✅ 列表渲染时必须提供唯一的 key
- ✅ 保持 JSX 简洁,提取复杂逻辑到组件或函数
下一步
在下一章中,我们将学习 React 组件的基础知识,了解如何创建和使用组件。
继续学习:下一章 - React 组件基础