关于react中使用index作key值render list的一点注意

首先,必须明确的是用index做key值是下下策,官方也不推荐,优先还是数据自己的id值。如果非要用index,且不满足安全情况时,建议在第一次获取数据的地方,为数据生成key值(比如api获取数据后)

怎样算满足安全情况?

1
2
3
<div>
{List.map((item, index) => <Item key={index} data={item} />)}
</div>
  1. List数组顺序不会发生改变(每条数据的index值恒定),比如不存在排序,过滤,插入,删除等可能导致数组顺序发生变化的行为

  2. Item中所有组件的状态均来自props,即不存在自己的state或者不受控制的状态,比如没有绑定value的<input />
    (注意,所谓的均来自props, 还不够准确,Item上所有的props值应当与index无关)

满足两条中任意一条,即可使用index作为key值而不会出现问题。否则只能为数组生成一下key值了(uuid或者timestamp + index等),即便不设,

If you choose not to assign an explicit key to list items then React will default to using indexes as keys.

React也会默认采用index做key值,然后你就发现你的程序好像挂了!

为啥会有问题

React官网有这样一句话

Component instances are updated and reused based on their key.

假设数组中有A,B两条记录,render出ItemA, ItemB

1
2
3
// [A, B].map =>
<Item key={0} data={A} />(ItemA号,key-0
<Item key={1} data={B} />(ItemB号, key-1

此时假如数组顺序变了,我们得到的新的结构是

1
2
3
// [B, A].map =>
<Item key={0} data={B} />(ItemA号, key-0
<Item key={1} data={A} />(ItemB号, key-1

我们期望的是ItemA和ItemB的顺序和数组一致,但是由于index做key值,对react来说ItemA和ItemB位置没有发生move,只不过ItemA和ItemB的props(data)变了。所以如果Item中所有状态均来自props/data,那么不会受到影响。但如果Item(包括其子组件)有自己维护的state或者不受控制的状态,则会出现问题。

比如

1
2
3
4
5
6
7
// [B, A] =>
<Item key={0} data={A}>
<Switch /> // state => { checked: true }
</Item>

<Item key={1} data={B}>
<Switch />// state => { checked: false }
</Item>

顺序转变后

1
2
3
4
5
6
7
// [B, A] =>
<Item key={0} data={B}>
<Switch /> // state => { checked: true }
</Item>(ItemA号)

<Item key={1} data={A}>
<Switch /> // state => { checked: false }
</Item>

原本A的那条记录应该被选中,但是顺序更改后变成记录B被选中了。

此时可以改一下代码

1
2
3
4
// [B, A] =>
{List.map((item, index) => <Item data={item} key={index}>
<Switch checked={item.checked} />
</Item>)}

就没有问题了。

参考

react 官网

文章目录
  1. 1. 怎样算满足安全情况?
  2. 2. 为啥会有问题
  3. 3. 参考
,