React中的key
key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。
这么说有点抽象,我们看一个例子:
state中有一个对象数组,里面存放着我们需要展示的人员信息:
state = {
objArr:[
{id:1,name:'何小幸',age:8},
{id:2,name:'何中幸',age:18},
{id:3,name:'何大幸',age:28}
]
}
我们在render中将其输出到页面:
render(){
return (
<ul>
this.state.objArr.map((obj,index)=>{
return <li key={index}>{obj.name},{obj.age}岁</li>
})
</ul>
)
}
可以看到我在li标签中写了key,那这里的key是做什么的呢?
我们继续往下看👇
有一天,我们的展示程序多了一个需求:要在所有人员后添加一个人,于是我写了一个对应的方法,绑定在按钮上,这样一按按钮,新来的人就可以添加到页面中:
add = ()=>{
let {objArr} = this.state
let obj = {id:4,name:"何不幸",age:38}
this.setState({objArr:objArr.push(obj)})
}
//对应的按钮(为突出重点,render等内容省略)
<button onClick={this.add}>点击这里在后方添加人员!</button>
于是接下来,我们点击按钮,人员添加,一套操作下来行云流水,看似成功完成,但实则暗藏玄机,接下来我们探究其底层刷新
原先的列表:
- 何小幸,8岁
- 何中幸,18岁
- 何大幸,28岁
更新后的列表:
- 何小幸,8岁
- 何中幸,18岁
- 何大幸,28岁
- 何不幸,38岁
在更新时发生了什么?是整个列表全部重新渲染,还是上方按兵不动,只添加了第四个人的小li?
答:只添加了第四个小li,在更新前,虚拟DOM会将原先的列表和更新后的列表进行对比,如果有的节点没有发生变化,那么就可以直接复用,不重新渲染,这样就节约了资源,使更新速度变快。
但React是怎么知道可不可以复用的呢?
答:通过key来判断,观察本例,前三人的key为0,1,2,在第四位添加进来后,前三位的key没有发生变化,于是三个小li就可以不重新渲染,页面中需要渲染的只有第四个新加的内容
以上就是key的作用,我们再来复习一遍:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。 而这个重要的作用就是通过标签节点的复用来进行资源节约。
具体更新规则:
-
旧的虚拟DOM中找到了与新虚拟DOM相同的key
- 如果虚拟DOM中的内容没变,直接使用之前的真实DOM
- 如果其中内容改变,则生成新的真实DOM,替换掉此前的DOM
-
旧虚拟DOM中没有找到与新虚拟DOM相同的key
- 根据数据创建新的真实DOM,然后再渲染到页面
我们这里要强调:
不要用index来当key!
为什么呢?
仍然是上方的例子,现在我们的列表为:
- 何小幸,8岁
- 何中幸,18岁
- 何大幸,28岁
- 何不幸,38岁
现在,我们要在第一位前插入新的成员数据,完成后列表为:
- 何微幸,0岁
- 何小幸,8岁
- 何中幸,18岁
- 何大幸,28岁
- 何不幸,38岁
看似没有问题,但实际上在对象数组中,因为首位插入了一条新数据,所以后方每一位的index都发生了改变,这也就导致了所有节点对应key的内容均发生了变化 (key=0原先是何小幸,现在变成了何微幸,后面以此类推) ,即使后面四位信息没有发生变化,也因为对应位置的变化,而进行了重新渲染,这样更新页面的效率就变得极其低下。
甚至,如果结构中包含输入类的DOM,还可能会引起错误的DOM更新,导致界面出现问题
所以,我们不建议使用index作为key,对应的,你应该为每一个节点取一个不容易发生变化的key,以此来保证更新的效率!