React中的key

99 阅读4分钟

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,以此来保证更新的效率!