JSX语法 #
一、什么是JSX #
JSX(JavaScript XML)是 JavaScript 的语法扩展,允许我们在 JavaScript 中编写类似 HTML 的代码。
1.1 JSX本质 #
javascript
// JSX语法
const element = <h1>Hello, React!</h1>;
// 编译后的JavaScript
const element = React.createElement('h1', null, 'Hello, React!');
1.2 为什么使用JSX #
| 优势 | 说明 |
|---|---|
| 直观 | UI 结构与逻辑放在一起 |
| 强大 | 可使用完整的 JavaScript 能力 |
| 类型安全 | 编译时发现错误 |
| 表达力强 | 支持条件、循环等逻辑 |
二、JSX基础语法 #
2.1 基本结构 #
javascript
// 单标签
const img = <img src="logo.png" alt="Logo" />;
// 双标签
const div = <div className="container">内容</div>;
// 嵌套结构
const card = (
<div className="card">
<h2>标题</h2>
<p>内容</p>
</div>
);
2.2 使用括号包裹 #
多行 JSX 使用括号包裹,避免自动插入分号:
javascript
const element = (
<div>
<h1>标题</h1>
<p>内容</p>
</div>
);
2.3 单个根元素 #
JSX 必须返回单个根元素:
javascript
// ❌ 错误:多个根元素
return (
<h1>标题</h1>
<p>内容</p>
);
// ✅ 正确:使用div包裹
return (
<div>
<h1>标题</h1>
<p>内容</p>
</div>
);
// ✅ 正确:使用Fragment
return (
<>
<h1>标题</h1>
<p>内容</p>
</>
);
// ✅ 正确:使用React.Fragment
return (
<React.Fragment>
<h1>标题</h1>
<p>内容</p>
</React.Fragment>
);
三、嵌入表达式 #
3.1 使用花括号 #
在 JSX 中使用 {} 嵌入 JavaScript 表达式:
javascript
const name = 'React';
const age = 10;
const element = (
<div>
<h1>Hello, {name}!</h1>
<p>Age: {age}</p>
<p>Next Year: {age + 1}</p>
</div>
);
3.2 可嵌入的内容 #
javascript
// 变量
const name = 'React';
<div>{name}</div>
// 表达式
<div>{1 + 1}</div>
<div>{'Hello'.toUpperCase()}</div>
// 函数调用
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
<div>{formatName({ firstName: 'React', lastName: 'JS' })}</div>
// 三元表达式
const isLoggedIn = true;
<div>{isLoggedIn ? '欢迎回来' : '请登录'}</div>
// 逻辑与运算符
const messages = ['msg1', 'msg2'];
<div>{messages.length > 0 && '有新消息'}</div>
3.3 不能嵌入的内容 #
javascript
// ❌ 不能嵌入语句
<div>{if (true) { return 'yes' }}</div>
<div>{for (let i = 0; i < 5; i++) { }}</div>
<div>{var x = 1}</div>
// ✅ 使用表达式替代
<div>{true ? 'yes' : 'no'}</div>
<div>{[1, 2, 3, 4, 5].map(i => i)}</div>
四、属性设置 #
4.1 字符串属性 #
javascript
// 使用引号
const img = <img src="logo.png" alt="Logo" />;
const div = <div className="container">内容</div>;
const input = <input type="text" placeholder="请输入" />;
4.2 动态属性 #
javascript
const imageUrl = 'logo.png';
const altText = 'Logo';
const img = <img src={imageUrl} alt={altText} />;
4.3 特殊属性名 #
HTML 属性在 JSX 中需要转换:
| HTML | JSX |
|---|---|
| class | className |
| for | htmlFor |
| tabindex | tabIndex |
| readonly | readOnly |
| maxlength | maxLength |
| onclick | onClick |
| onchange | onChange |
javascript
// ❌ 错误
<div class="container">
<label for="name">Name</label>
</div>
// ✅ 正确
<div className="container">
<label htmlFor="name">Name</label>
</div>
4.4 布尔属性 #
javascript
// 省略值表示true
<input disabled />
<input required />
// 显式设置
<input disabled={true} />
<input disabled={false} />
4.5 data-* 和 aria-* 属性 #
javascript
<div data-id="123" data-name="test">内容</div>
<button aria-label="关闭">X</button>
五、样式设置 #
5.1 内联样式 #
javascript
const style = {
color: 'red',
fontSize: '16px',
backgroundColor: '#f0f0f0',
padding: '10px 20px'
};
const div = <div style={style}>内容</div>;
// 直接写对象
const div2 = (
<div style={{
color: 'blue',
fontSize: '14px'
}}>
内容
</div>
);
注意:
- 使用 camelCase 命名
- 值可以是字符串或数字
- 数字会自动添加 px
5.2 CSS类名 #
javascript
// 单个类名
<div className="container">内容</div>
// 多个类名
<div className="container active">内容</div>
// 动态类名
const isActive = true;
<div className={`container ${isActive ? 'active' : ''}`}>
内容
</div>
// 使用模板字符串
const size = 'large';
<div className={`button button-${size}`}>
按钮
</div>
5.3 使用classnames库 #
bash
npm install classnames
javascript
import classNames from 'classnames';
function Button({ primary, size, disabled }) {
const btnClass = classNames('btn', {
'btn-primary': primary,
'btn-large': size === 'large',
'btn-small': size === 'small',
'btn-disabled': disabled
});
return <button className={btnClass}>按钮</button>;
}
六、条件渲染 #
6.1 if语句 #
javascript
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>欢迎回来!</h1>;
}
return <h1>请登录</h1>;
}
6.2 三元表达式 #
javascript
function Greeting({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <h1>欢迎回来!</h1> : <h1>请登录</h1>}
</div>
);
}
6.3 逻辑与运算符 #
javascript
function Mailbox({ unreadMessages }) {
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 && (
<h2>你有 {unreadMessages.length} 条未读消息</h2>
)}
</div>
);
}
6.4 立即执行函数 #
javascript
function Component({ type }) {
return (
<div>
{(() => {
switch (type) {
case 'a': return <A />;
case 'b': return <B />;
default: return <C />;
}
})()}
</div>
);
}
七、列表渲染 #
7.1 map方法 #
javascript
const fruits = ['Apple', 'Banana', 'Orange'];
const list = (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
7.2 对象列表 #
javascript
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 }
];
const userList = (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} - {user.age}岁
</li>
))}
</ul>
);
7.3 key的重要性 #
javascript
// ✅ 使用唯一ID作为key
{items.map(item => <li key={item.id}>{item.name}</li>)}
// ⚠️ 避免使用index作为key(列表会变化时)
{items.map((item, index) => <li key={index}>{item.name}</li>)}
// ❌ 不要使用不稳定的key(如随机数)
{items.map(item => <li key={Math.random()}>{item.name}</li>)}
key的作用:
- 帮助 React 识别列表项的变化
- 提高列表更新性能
- 保持组件状态正确
八、事件处理 #
8.1 绑定事件 #
javascript
function Button() {
const handleClick = () => {
console.log('按钮被点击');
};
return <button onClick={handleClick}>点击我</button>;
}
8.2 传递参数 #
javascript
function List() {
const handleClick = (id, event) => {
console.log('ID:', id);
console.log('Event:', event);
};
return (
<ul>
<li onClick={(e) => handleClick(1, e)}>Item 1</li>
<li onClick={(e) => handleClick(2, e)}>Item 2</li>
</ul>
);
}
8.3 阻止默认行为 #
javascript
function Form() {
const handleSubmit = (e) => {
e.preventDefault();
console.log('表单提交');
};
return (
<form onSubmit={handleSubmit}>
<button type="submit">提交</button>
</form>
);
}
九、组件使用 #
9.1 使用组件 #
javascript
function Header() {
return <h1>Header</h1>;
}
function Content() {
return <p>Content</p>;
}
function App() {
return (
<div>
<Header />
<Content />
</div>
);
}
9.2 组件属性 #
javascript
function Welcome({ name, age }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>Age: {age}</p>
</div>
);
}
function App() {
return (
<div>
<Welcome name="Alice" age={25} />
<Welcome name="Bob" age={30} />
</div>
);
}
9.3 children属性 #
javascript
function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-body">
{children}
</div>
</div>
);
}
function App() {
return (
<Card title="标题">
<p>这是卡片内容</p>
<button>按钮</button>
</Card>
);
}
十、JSX最佳实践 #
10.1 代码组织 #
javascript
// ✅ 好的做法:逻辑与渲染分离
function UserList({ users }) {
const activeUsers = users.filter(user => user.isActive);
const sortedUsers = activeUsers.sort((a, b) => a.name.localeCompare(b.name));
return (
<ul>
{sortedUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
10.2 条件渲染优化 #
javascript
// ✅ 复杂条件抽取为函数
function getStatusText(status) {
switch (status) {
case 'loading': return '加载中...';
case 'success': return '成功';
case 'error': return '出错了';
default: return '未知状态';
}
}
function Component({ status }) {
return <div>{getStatusText(status)}</div>;
}
10.3 避免嵌套过深 #
javascript
// ❌ 嵌套过深
return (
<div>
<div>
<div>
<div>
<span>内容</span>
</div>
</div>
</div>
</div>
);
// ✅ 使用Fragment或拆分组件
return (
<>
<Header />
<Main />
<Footer />
</>
);
十一、总结 #
| JSX规则 | 说明 |
|---|---|
| 单根元素 | 返回一个父元素 |
| 闭合标签 | 所有标签必须闭合 |
| camelCase | 属性使用驼峰命名 |
| className | 使用 className 代替 class |
| 花括号 | 使用 {} 嵌入表达式 |
| key属性 | 列表渲染需要唯一 key |
核心要点:
- JSX 是语法糖,编译为 JavaScript
- 使用 {} 嵌入 JavaScript 表达式
- 属性使用驼峰命名
- 条件渲染使用三元表达式或逻辑与
- 列表渲染使用 map 方法
最后更新:2026-03-26