在React开发中,列表渲染是非常常见的需求,比如从接口拿到数组数据后需要展示成多个列表项。很多刚接触React的开发者会尝试在JSX中直接写for循环或者while循环,往往会触发语法错误,这是因为JSX本质上是JavaScript的语法扩展,它不支持原生的流程控制语句直接嵌入到花括号中。

为什么JSX中不能直接写循环语句
JSX在编译时会被转换成React.createElement的调用形式,其中花括号{}内部只能放置可执行的JavaScript表达式,而for、while这类语句属于语句而非表达式,无法直接放在{}中使用,因此会出现意外的token这类报错。要实现列表渲染,需要用到数组的map方法,因为map本身是表达式,会返回一个新的数组,符合JSX的语法要求。
正确的列表渲染方式
基础map渲染示例
首先需要准备一个待渲染的数组数据,然后调用map方法遍历数组,为每个元素返回对应的JSX节点即可。下面是一个最简单的示例:
import React from 'react';
function ListDemo() {
// 待渲染的列表数据
const fruitList = ['苹果', '香蕉', '橙子', '葡萄'];
return (
<div className="list-container">
<h3>水果列表</h3>
<ul>
{fruitList.map((item, index) => {
// 每个列表项需要设置唯一的key属性
return <li key={index}>{item}</li>;
})}
</ul>
</div>
);
}
export default ListDemo;key属性的注意事项
在使用map渲染列表时,必须为每个生成的节点设置key属性,这是React用来识别哪些元素被修改、添加或者删除的辅助标识。需要注意以下几点:
- key的值要在兄弟节点之间保持唯一,不需要全局唯一
- 尽量不要使用数组的索引作为key,除非列表是静态的、不会重新排序、不会过滤,否则在数据变化时可能导致渲染异常
- 如果列表数据有唯一的id字段,优先使用id作为key
带复杂数据的渲染示例
实际开发中列表数据往往是对象数组,每个对象包含多个属性,这时候可以在map中解构对象,渲染更复杂的内容:
import React from 'react';
function UserList() {
// 对象类型的列表数据
const userList = [
{ id: 1, name: '张三', age: 25, job: '前端开发' },
{ id: 2, name: '李四', age: 28, job: '后端开发' },
{ id: 3, name: '王五', age: 22, job: '测试工程师' }
];
return (
<div className="user-list">
<h3>用户列表</h3>
<table border="1" cellPadding="8" cellSpacing="0">
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>职位</th>
</tr>
</thead>
<tbody>
{userList.map(user => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{user.job}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default UserList;常见错误及规避方式
错误1:在JSX中直接写for循环
很多开发者会写出下面的错误代码,导致编译报错:
// 错误示例,会触发语法错误
function WrongList() {
const list = [1,2,3];
return (
<ul>
{for (let i=0; i<list.length; i++) {
return <li key={i}>{list[i]}</li>
}}
</ul>
);
}规避方式:把循环逻辑放到JSX外部,或者直接使用map方法,不要在{}中嵌入语句。
错误2:忘记返回JSX节点
使用map时如果没有返回对应的节点,会导致列表渲染为空,比如下面的错误写法:
// 错误示例,map没有返回值
function NoReturnList() {
const list = ['a','b','c'];
return (
<ul>
{list.map(item => {
<li key={item}>{item}</li> // 没有return,不会渲染内容
})}
</ul>
);
}规避方式:如果使用大括号包裹map的回调函数,记得添加return语句;如果使用箭头函数的简写形式,可以省略大括号和return。
错误3:在循环中使用条件判断逻辑混乱
如果需要在循环中根据条件渲染不同的内容,可以直接在map的回调函数中使用三元表达式或者逻辑与运算符,不需要额外嵌套复杂的判断:
import React from 'react';
function ConditionalList() {
const taskList = [
{ id: 1, content: '完成需求文档', done: true },
{ id: 2, content: '开发列表组件', done: false },
{ id: 3, content: '提交测试', done: false }
];
return (
<ul>
{taskList.map(task => (
<li key={task.id} style={{ color: task.done ? 'gray' : 'black' }}>
{task.done ? `✓ ${task.content}` : task.content}
</li>
))}
</ul>
);
}
export default ConditionalList;循环逻辑的提取优化
如果列表渲染的逻辑比较复杂,或者多个组件都需要用到相同的列表渲染逻辑,可以把map的处理逻辑提取到JSX外部,让代码更清晰:
import React from 'react';
function OptimizedList() {
const bookList = [
{ id: 1, title: 'React实战', price: 89 },
{ id: 2, title: 'JavaScript高级程序设计', price: 129 },
{ id: 3, title: 'CSS世界', price: 69 }
];
// 把循环逻辑提取到外部
const renderBookList = () => {
return bookList.map(book => (
<div className="book-item" key={book.id}>
<span>书名:{book.title}</span>
<span>价格:{book.price}元</span>
</div>
));
};
return (
<div className="book-list">
<h3>图书列表</h3>
{renderBookList()}
</div>
);
}
export default OptimizedList;掌握以上这些要点,就可以在React JSX中正确、规范地实现列表循环渲染,规避常见的语法错误,写出可维护性更高的React组件代码。