React中key的必要性与使用

  |  
 阅读次数

React中key的必要性与使用

关键词:diff算法 唯一标识

当React作diff时,只要子元素有key属性,便会去原v-dom树中相应位置(当前横向比较的层级)寻找是否有同key元素,比较它们是否完全相同若是则复用该元素,免去不必要的操作。

key必须是字符串类型,它的取值可以用数据对象的某个唯一属性,或是对数据进行hash来生成key。

强烈 不推荐 用数组index来作为key。如果数据更新仅仅是数组重新排序或在其中间位置插入新元素,那么视图元素都将重新渲染。来看下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
<ul>{list.map((v,idx)=><li key={idx}>{v}</li>)}</ul>
// ['a','b','c']=>
<ul>
<li key="0">a</li>
<li key="1">b</li>
<li key="2">c</li>
</ul>
// 数组重排 -> ['c','a','b'] =>
<ul>
<li key="0">c</li>
<li key="1">a</li>
<li key="2">b</li>
</ul>

React发现key为0,1,2的元素的text都变了,将会修改三者的html,而不是移动它们。

渲染同类型元素不带key只会产生性能问题; 如果渲染的是不同类型的状态性组件,组件将会被替换,状态丢失。

1
2
3
4
{this.state.type ? 
(<div><Son_1 /><Son_2 /></div>)
: (<div><Son_2 /><Son_1 /></div>)
}

如上述代码,每次按下按钮,原 Son_1与Son_2 组件的实例都将被销毁并创建新的Son_1与Son_2实例不能继承原来的状态;而它们实际上只是调换了位置。给它们加上key可避免问题:

1
2
3
4
{this.state.type ? 
(<div><Son_1 key="1"/><Son_2 key="2"/></div>)
: (<div><Son_2 key="2"/><Son_1 key="1"/></div>)
}

结论:

  1. 使用唯一id作为key比使用 index 作为 key 性能更好
  2. 移动节点比修改节点的html 性能更好

分析补充:\
使用 index 作为 key 某些情况下影响性能。\
举个例子:
一个数组[a,b],渲染成两个不同类型的节点,key用index。然后数组变成[b,a],\
再次渲染时,react先判断变化前后同key的虚拟节点是否相等,发现节点类型就不同,接下来的操作就是新建两个dom节点去替换原来的节点。这种情况下key等于没用。而如果用唯一id,react会知道同key节点没有变化,只是换了位置,只要打个移动节点的patch到dom上,而不是新建替换。
另外修改节点可能修改量无限大啊