前言
这个面试题是我在学习React框架时遇见的一道经典的前端面试题,如果你对我的React系列文章有兴趣的话,欢迎各位道友来看看我的React–从入门到实战专栏(点这里)。
经典面试题:
- react/vue中的key有什么作用?(key的内部原理是什么?)
- 为什么遍历列表时,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.state
const 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. 所有, 如有侵权,请联系我们删除。