前端经典面试题-react/vue为什么不能用index做key

2022-06-29 14:05:31

前言

这个面试题是我在学习React框架时遇见的一道经典的前端面试题,如果你对我的React系列文章有兴趣的话,欢迎各位道友来看看我的React–从入门到实战专栏(点这里)。


经典面试题:

  1. react/vue中的key有什么作用?(key的内部原理是什么?)
  2. 为什么遍历列表时,key最好不要用index?

在了解index为什么不可以做key之前,先来看看key的作用:

1、react/vue中key的作用与原理

虚拟DOM中key的作用:

  • 简单的说,key是虚拟DOM对象的标识,在更新显示时起着及其重要的作用。

  • 详细的说,当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,随后react进行【新虚拟DOM】与【旧虚拟DOM】的Diffing比较,比较规则如下:

    • 旧虚拟DOM中找到了与新虚拟DOM相同的key:

    • (1)、若虚拟DOM中内容没变,直接使用之前的真实DOM;

      (2)、若虚拟DOM中内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOM

    • 旧虚拟DOM中未找到与新虚拟DOM相同的key:

    • 根据数据创建新的真实DOM,随后渲染到页面

2、index做key可能引发的问题

  • 用index作为key可能会引发的问题

    • a、若对数据进行:逆序添加、逆序删除等破坏顺序操作:

      会产生没有必要的真实DOM更新 => 界面效果没问题,但效率低

    • b、如果结构中还包含输入类的DOM:

      会产生错误DOM更新 => 界面有问题

    • 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

  • 开发中如何选择key?

    最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。

3、index与id做key的对比示例

在这里插入图片描述

说明

在使用index作为key时,输入框(任何输入型的dom)内容明显发生了错误,小张的信息跑到小王的输入框里去了。这是因为,在添加小王之前,小张的输入框的key是小张的那一行< li >标签对应的index值(key = 0),在添加小王之后,小王那一行的< li >标签对应的index变成了0(key = 0),Diffing算法检测dom的最小粒度是html标签,检测到 li标签的小王的li标签key为0,就把之前小张的内容放到小王那一行去了。


示例的代码实现

<script type="text/babel">classPersonextendsReact.Component{
      state={persons:[{id:1,name:'小张',age:18},{id:2,name:'小李',age:19}]}add=()=>{const{ persons}=this.stateconst p={id: persons.length+1,name:'小王',age:20}this.setState({persons:[p,...persons]});}render(){return(<div><h2>展示人员信息</h2><button onClick={this.add}>添加一个小王</button><h3>使用index索引值作为key</h3><ul>{this.state.persons.map((personObj, index)=>{return<li key={index}>{personObj.name}---{personObj.age}<input type="text"/></li>})}</ul><hr/><hr/><h3>使用id数据的唯一标识作为key</h3>{this.state.persons.map((personObj)=>{return<li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text"/></li>})}</div>);}}
    ReactDOM.render(<Person/>, document.getElementById('test'))</script>

代码解释

/* 
      慢动作回放————使用index索引值作为key
      
      初始数据:
        { id: 1, name: '小张', age: 18 },
        { id: 2, name: '小李', age: 19 }
      初始虚拟DOM:
        <li key=0>小张---18</li>
        <li key=1>小李---19</li>

      更新后的数据:
        { id: 3, name: '小王', age: 20 },
        { id: 1, name: '小张', age: 18 },
        { id: 2, name: '小李', age: 19 }

      更新后的虚拟DOM:
        <li key=0>小王---20</li>
        <li key=1>小张---18</li>
        <li key=2>小李---19</li>

      更新后的虚拟DOM与初始虚拟DOM比较
          key为0的内容不一样,重新渲染真实DOM;
          key为1的内容不一样,重新渲染真实DOM;
          key为2,初始虚拟DOM中不存在,重新渲染真实DOM;
        导致小张、小李这两个可以复用的内容也无法复用,这就是index索引值作为key的缺陷。


      慢动作回放————使用id唯一标识作为key
      
      初始数据:
        { id: 1, name: '小张', age: 18 },
        { id: 2, name: '小李', age: 19 }
      初始虚拟DOM:
        <li key=1>小张---18</li>
        <li key=2>小李---19</li>

      更新后的数据:
        { id: 3, name: '小王', age: 20 },
        { id: 1, name: '小张', age: 18 },
        { id: 2, name: '小李', age: 19 }

      更新后的虚拟DOM:
        <li key=3>小王---20</li>
        <li key=1>小张---18</li>
        <li key=2>小李---19</li>

      更新后的虚拟DOM与初始虚拟DOM比较
          key为3,初始虚拟DOM中不存在,转为真实DOM放到页面;
          key为1(小张),更新后与初始虚拟DOM,内容一样,不做更改,复用;
          key为2(小李),更新后与初始虚拟DOM,内容一样,不做更改,复用;
        使用id作为key,效率明显提高许多。
*/

好啦~今天的文章就先到这里啦,如果在文章中发现错误还请各位道友私信我以便更改~

原创不易,如果对你有帮助的话,请不要吝啬你的三连哟✅~

感谢各位道友的支持✅回见~

在这里插入图片描述

  • 作者:codeMak1r.
  • 原文链接:https://blog.csdn.net/Svik_zy/article/details/125053174
    更新时间:2022-06-29 14:05:31