专栏首页OECOMreact中key的作用是什么

react中key的作用是什么

key这个属性一般是在输出循环列表时,react要求我们填写的一个属性,如果不填的话,在控制台会给出警告,当然页面渲染也是可以正常渲染的,但是可能会引发一些不确定的bug,所以我们在写循环列表输出时还是建议将key这个属性带上。

那么这个属性究竟有什么用处呢?我们来看一下下面这个例子:

{
    this.state.users&&this.state.users.map(item=>{

        return <li key={item.id}>{item.name}: 来啦</li>
    })
}

上面这行代码是我们平时作为列表显示的写法,假设我们这个users中有4个成员:张三、李四、王五、马六;那么其输出结果为:

<li>张三: 来啦</li>
<li>李四: 来啦</li>
<li>王五: 来啦</li>
<li>马六: 来啦</li>

其实正常来说这个key写与不写输出结果都是这个结果,写与不写的区别主要在于更新上。当我们需要渲染一个列表的时候,React 会存储这个列表每一项的相关信息,当我们要更新这个列表时,React需要确定哪些项发生了改变。我们有可能增加、删除、重新排序或者更新列表项。

在react中采用的是diff算法来对比新旧虚拟节点,从而更新节点。 在交叉对比中,当新节点跟旧节点头尾交叉对比没有结果时,会根据新节点的key去对比旧节点数组中的key,从而找到相应旧节点(这里对应的是一个key => index 的map映射)。如果没找到就认为是一个新增节点。而如果没有key,那么就会采用遍历查找的方式去找到对应的旧节点。一种一个map映射,另一种是遍历查找。相比而言。map映射的速度更快。

其实如果说只是文本内容改变了,不写key反而性能和效率更高,主要是因为不写key是将所有的文本内容替换一下,节点不会发生变化,而写key则涉及到了节点的增和删,发现旧key不存在了,则将其删除,新key在之前没有,则插入,这就增加性能的开销。当然在我们正常的开发中,这种及其简单的更新是很少见的,大部分还是复杂的内容更新,所以按大局来说还是写key的效率高一些,写key增加的这一点点的性能开销在用户的视角上时感知不到的。

所以说key是给每一个vnode的唯一id,可以依靠key,更准确, 更快的拿到oldVnode中对应的vnode节点,高效和准确的更新节点

误区

很多人在写key是通常是将循环的index值写入,这样又写了key,react也不会给出警告了,其实这和没写是一样的。因为在react中如果你没有指定任何 key,react 会发出警告,并且会把数组的索引当作默认的 key。但是如果想要对列表进行重新排序、新增、删除操作时,把数组索引作为 key 是有问题的。显式地使用 key={i} 来指定 key 确实会消除警告,但是仍然和数组索引存在同样的问题,所以大多数情况下最好不要这么做。

这里我来举一个例子来说明一下用索引当key或者不写key会引发什么问题。下面我以百度首页为例(登录之后的):

他的顶部有两个导航,下面是新闻列表,如果我们的列表没有用稿件的ID做为key或者用索引当key会出现什么问题呢?当初次渲染时,基本没有问题,当点击导航这个标签时,我们会请求导航栏目下的新闻稿件,然后渲染到页面上,因为新闻的结构大部分都是如上图所示的,上面标题下面图片,左边图片右边标题,如果没有唯一key,切换的时候回发现栏目内容都换了,但是图片没有变,还是之前的图,过一会儿以后才会变过来。这就是因为他会将所有的列表遍历替换内容,节点不变化,而图片的src变化后,需要全部加载完成之后才会显示为新的图片,如果以稿件ID为key则不会出现这种情况,有兴趣的可以自己试一试,当然如果网络很好,图片加载快,这种现象不会很明显。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • redis命令之操作字符串

    Redis的字符串就是一个由字节组成的序列,他们和很多编程语言里的字符没有什么明显区别,更多的适合js中的字符串类似,字符串可以存储以下三张从类型的值: - ...

    无邪Z
  • 多功能响应式兼容IE8图片轮播

    前段时间在写一个官网,官网中很多地方都用到了图片轮播,但是需求中要求网站适配到IE8同时具有自适应的特点,适配各种尺寸的浏览器和移动端浏览器。于是我尝试了在网上...

    无邪Z
  • redis命令之操作列表

    Reids是可以操作列表的,列表是一种数据结构,在redis中,它允许用户从列表的两端推入或者弹出数据、获取列表数据以及执行各种常见的列表操作。初次之外,列表还...

    无邪Z
  • 手写JDK7-HashMap

    现在一般都JDK8了,为什么还要说JDK7呢。因为JDK7和JDK8的hashmap实现不一样,JDK7是用数组+链表实现的,而JDK8是红黑树。学习都是个慢慢...

    DH镔
  • 使用Python读取plist文件并分割

    根据百度百科介绍,plist是一种文件形式,通常用于储存用户设置,也可以用于存储捆绑的信息,该功能在旧式的Mac OS中是由资源分支提供的。由于Plist中存储...

    py3study
  • Redis的过期策略和内存淘汰策略及LRU算法详解

    设置key的过期时间。超时后,将会自动删除该key。在Redis的术语中一个key的相关超时是volatile的。

    JavaEdge
  • redis命令之操作字符串

    Redis的字符串就是一个由字节组成的序列,他们和很多编程语言里的字符没有什么明显区别,更多的适合js中的字符串类似,字符串可以存储以下三张从类型的值: - ...

    无邪Z
  • redis学习教程之一基本命令

    参阅redis中文的 互动教程(interactive tutorial)的学习笔记。 全局操作: #查看所有key keys * 或 keys "*" ...

    Ryan-Miao
  • Redis并发问题

    我们都知道Redis 是单线程的,那么如果单单是放一次以供查询,或者使用list追加放入以供查询,基本上没有太大的问题。但是如果说要根据原有的数据进行计算,怎么...

    yaphetsfang
  • 百亿关系链,架构如何设计?

    粉丝与关注,社交好友,都是典型的“多对多关系”的业务,这类业务的核心服务是好友中心,当关系链达到百亿之后,好友中心架构设计要考虑哪些因素,是本文将要分享的内容。

    架构师之路

扫码关注云+社区

领取腾讯云代金券