function ShoppingList({ list }) {
return (
<form>
{list.map(item => (
<p>
You bought {item.name}
<br />
Enter how many do you want: <input />
</p>
))}
</form>
)
}
如果我们的商品列表被重新排序了,React 只会看到所有的 p 以及里面的 input 拥有相同的类型,并不知道该如何移动它们。(在 React 看来,虽然这些商品本身改变了,但是它们的顺序并没有改变。)
所以 React 会对这十个商品进行类似如下的重排序:
for (let i = 0; i < 10; i++) {
let pNode = formNode.childNodes[i];
let textNode = pNode.firstChild;
textNode.textContent = 'You bought ' + items[i].name;
}
React 只会对其中的每个元素进行更新而不是将其重新排序。这样做会造成性能上的问题和潜在的 bug 。例如,当商品列表的顺序改变时,原本在第一个输入框的内容仍然会存在于现在的第一个输入框中 — 尽管事实上在商品列表里它应该代表着其他的商品! 。例如,当商品列表的顺序改变时,原本在第一个输入框的内容仍然会存在于现在的第一个输入框中 — 尽管事实上在商品列表里它应该代表着其他的商品!
这就是为什么每次当输出中包含元素数组时,React 都会让你指定一个叫做 key 的属性:
function ShoppingList({ list }) {
return (
<form>
{list.map(item => (
<p key={item.productId}>
You bought {item.name}
<br />
Enter how many do you want: <input />
</p>
))}
</form>
)
}
key 给予 React 判断子元素是否真正相同的能力,即使在渲染前后它在父元素中的位置不是相同的
当 React 在 中发现
,它就会检查之前版本中的 是否同样含有
。即使 中的子元素们改变位置后,这个方法同样有效。在渲染前后当 key 仍然相同时,React 会重用先前的宿主实例,然后重新排序其兄弟元素。
需要注意的是 key 只与特定的父亲 React 元素相关联,比如 。React 并不会去匹配父元素不同但 key 相同的子元素。(React 并没有惯用的支持对在不重新创建元素的情况下让宿主实例在不同的父元素之间移动。)
给 key 赋予什么值最好呢?最好的答案就是:什么时候你会说一个元素不会改变即使它在父元素中的顺序被改变? 例如,在我们的商品列表中,商品本身的 ID 是区别于其他商品的唯一标识,那么它就最适合作为 key 。