列表和 key
假设你正在构建一个待办事项列表:几个项目,每个都有自己的文本,来自一个 todo 对象数组。React 没有专门的列表组件来把数组转换成标记。你使用纯 JavaScript 的 map 把每一项转换成一段 JSX,React 就渲染出结果。
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
)
}用 map 渲染列表
那个 todos 数组通常来自从拥有实际数据的父组件传下来的 prop。todos.map 遍历数组,为每个 todo 返回一个 <li>。外面的花括号把那个 JSX 元素数组直接放进 <ul> 里,就像放一个单独的表达式一样。每个 <li> 还需要一个 key prop,设置为 todo.id。如果你想让列表表现正确,这一部分不是可选的:跳过它,React 仍然会渲染这个列表,但会在控制台记录一个警告,下面描述的重排 bug 一旦列表改变形状就会成为真正的风险。
key 是 React 用来区分列表项的方式,从一次渲染到下一次。它必须在兄弟元素中唯一,所以这个列表中没有两个 <li> 元素共享一个 key,而且它必须是稳定的,意思是相同的 todo 在每次列表重新渲染时都得到相同的 key。来自你的数据的 id,比如 todo.id,正好就是这样:它属于 todo,而不是属于它在数组中的位置,所以即使周围的列表改变,它也保持不变。
为什么数组索引作为 key 不好
这就是为什么数组索引作为 key 不好。这很诱人,因为每个数组已经有一个了:
{todos.map((todo, index) => (
<li key={index}>{todo.text}</li>
))}只要列表从不重排,从不插入或删除项目,这就工作得很好。一旦它这样做,索引就停止匹配它曾经指向的项目。删除第一个 todo,其他每一项都向上移动一个索引,所以 React 看到相同的 key 附加到了不同的 todo。如果那些列表项中有任何一个持有自己的状态,比如一个正在编辑的复选框或有人正在输入的输入框,那个状态会停留在这个索引上,最后出现在错误的行。把索引当作静态列表的备选方案,这些列表从不重排。在其他任何地方都用真正的 id。
map 把数组转成元素列表时,给每个加一个 key,并使用来自你数据的真正 id,而不是它在数组中的位置。key 是 React 如何在渲染之间跟踪哪个元素是哪个的方式,一个属于项目的 id 即使列表被重排也保持正确。 接下来:State,组件开始在渲染之间记住东西的地方。

