React/vue中的key

说到key值,学过vue的童鞋,对此并不陌生。
我们在面试的时候也是会经常被问到类似问题:
1、在React/vue中key值得作用或者工作原理。
2、为什么在遍历数据时,不使用index索引值作为key?
3、开发中如何选择key值?

diffing算法

要讲key,避无可避就需要先了解下diffing算法。
看下面栗子:

class Time extends React.Component{
        state={
            date:new Date()
        }
        componentDidMount(){
            setInterval(()=>{
                this.setState({
                    date:new Date()
                })
            },1000)
        }
        render(){
            return (
                <div>
                    <h1>Hello World!^-^</h1>
                    <div><input type="text"/></div>
                    <h2>
                        现在是北京时间:{this.state.date.toTimeString()}
                    </h2>
                </div>
            )
        }
    }
    ReactDOM.render(<Time/>,document.getElementById('test'))

这是个时间组件,每隔一秒就会更新页面中的时间。
在input框里输入文字,我们发现,随着时间文字的变化,输入框里的文字并没有变化,是怎么回事呢?
简单来说,在每一次更新数据后 ,h1和div下的input的DOM没发生变化,这时候就没有触发生成新的虚拟dom。
而h2里的时间,每隔一秒就做了一次setState的更新,那么整个h2标签都会重新渲染。
这里要注意,react的渲染最小颗粒度是标签。
那如果在h2里,再放一个input框,会怎样?

<h2>
   现在是北京时间:{this.state.date.toTimeString()}
   <input type="text"/>
</h2>

我们发现,h2内部的input框也没有发生变化。这说明,diffing算法并不是指计算最外层的。它会从外到里每一层去过滤,如果有标签存在就去做对比。
话锋硬转~,我们回到最开始的问题。先仔细读一下下方的代码示例。

class Person extends React.Component{
        state = {
            persons:[
                {id:1,name:'小张',age:17},
                {id:2,name:'小黄',age:19},
            ]
        }
        add= ()=>{
            let {persons} = this.state
            const p = {id:3,name:'小杨',age:20}
            this.setState({persons:[p,...persons]})
        }
        render(){
            const {persons} = this.state
            return (
                <div>
                    <h1>学生信息展示</h1>
                    <button onClick={this.add}>添加新学生</button>
                    <hr/>
                    <ul>
                        {
                            persons.map((item,index)=>{
                               return <li key={index}>姓名:{item.name} 年龄:{item.age}<input type="text" /></li>
                            })
                        }
                    </ul>
                </div>
            )
        }
    }
    ReactDOM.render(<Person/>,document.getElementById('test'))

1、虚拟DOM中key的作用:

key是react/vue渲染从虚拟dom渲染真实dom时的唯一标识。合理的使用key,可以提高渲染效率。
工作原理:当状态中的数据发生变化时,react会根据新数据生成【新的虚拟dom】,随后,react进行【新虚拟dom】与【旧虚拟dom】的diff对比,比较规则如下:

a.旧虚拟dom中找到了与新虚拟dom相同的key值:
          (1)若虚拟dom中的内容没变,直接使用之前的真实dom
          (2)若虚拟dom中的内容变了,则生成新的真实DOM
b.旧虚拟dom中未找到与新虚拟dom相同的key:
          根据数据创建新的真实DOM

2、用index作为key可能会引发问题:

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

示例中,展示了学生信息,并且以index为key值。当点击按钮时,向数据列表首位插入一条新数据。我们发现并没有什么影响,页面信息显示正常。
但如果,加入上边的规则分析一下,就会发现,这里有很大的效率问题。
初始数据:

*		初始数据:
*           {id:1,name:'小张',age:17},
*           {id:2,name:'小黄',age:19}
*       初始虚拟dom
*           <li key=0>id:1 姓名:小张 年龄:17</li>
*           <li key=1>id:2 姓名:小黄 年龄:19</li>
*       更新后的DOM
*           <li key=0>id:3 姓名:小杨 年龄:20</li>
*           <li key=1>id:1 姓名:小张 年龄:17</li>
*           <li key=2>id:2 姓名:小黄 年龄:19</li>
*   在key值对比过程中,依照上边的规则,所有的旧真实dom全部被替换。
如果使用数据唯一标识作为key会怎样?
* 		初始数据:
*           {id:1,name:'小张',age:17},
*           {id:2,name:'小黄',age:19}
*       初始虚拟dom
*           <li key=1>id:1 姓名:小张 年龄:17</li>
*           <li key=2>id:2 姓名:小黄 年龄:19</li>
*       更新后的DOM
*           <li key=3>id:3 姓名:小杨 年龄:20</li>  //只有第一条是重新渲染的真实DOM
*           <li key=1>id:1 姓名:小张 年龄:17</li>  //以下两条都可以在旧的虚拟dom中找到相同的key值,并且内容不便。真实dom沿用旧的。
*           <li key=2>id:2 姓名:小黄 年龄:19</li>

b.如果结构中还包含输入类的DOM,会产生错误的dom更新->界面有问题。

*       初始虚拟dom
*           <li key=0>id:1 姓名:小张 年龄:17<input type="text"></li>
*           <li key=1>id:2 姓名:小黄 年龄:19<input type="text"></li>
*       更新后dom
*           <li key=0>id:3 姓名:小杨 年龄:20<input type="text"></li>
*           <li key=1>id:1 姓名:小张 年龄:17<input type="text"></li>
*           <li key=2>id:2 姓名:小黄 年龄:19<input type="text"></li>
*       当数据发生变化时,首先对比最外层标签li的key值,发现在旧虚拟dom中存在key为0的dom,之后对比内容,内容不一样。然后再对比内部的input的标签,发现input的标签没发生变化。
*       那么更新的dom结构里不包含input的框,继续沿用。
*       所以就会有input框内值错位的现象。
c.注意!如果不存在对数据的逆序添加、逆序删除等破坏数据顺序的操作。仅用于渲染列表,使用index作为key值没有问题。

3、开发中如何选择key?

     a、最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值。
    b、如果确定只是简单的展示数据,用index也是可以的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值