React hooks系列 页面渲染时的key值

140 阅读3分钟

React hooks系列 页面渲染时的key值

前言

react的渲染列表时要带上Key一直是面试的高频考点。

但我们往往使用它是为了使控制台中的警告消失,却忽略了key使用不当带来性能上的问题。

以下主要从三方面去讲解key

image.png

目录

一、 key的作用

二、 key带来的性能问题

三、 如何正确的使用key

一、key的作用

key的作用:在渲染的时候告诉React每个组件或者JSX标签对应于哪个数组项,以便后面的操作可以匹配上它们。如果数组项需要移动(例如由于排序)、插入或删除,它作为唯一标识就变得很重要。

一个独一无二的的key可以帮助React辨别接下来到底发生了什么,并对DOM树进行正确的更新。

上面讲述可能有点抽象,来个易懂例子:

想象一下桌面上的文件没有名称。取而代之的是,您需要提前把他们排好 - 第一个文件,第二个文件等。

image.png

刚开始是可以知道各自文件里的内容,但是删除文件后,它将变得令人困惑。第二个文件将成为第一个文件,第三个文件将是第二个文件,依此类推这样再往复几轮这种新增、删除和排序的操作,就彻底分不清哪些文件对应哪些内容了。

文件夹中的文件名和数组中数据项的key具有类似的目的。key让我们独特地识别其相邻数据项之间的关系。即使该位置因重新排序而变化,key也可以在React整个生命周期中识别该数据项。

二、key带来的性能问题

有时候往往我们数组的数据项中找不到唯一的key值,我们往往会通过map中的index作为key, 实际上,这根本就不是指定一个key,即使react在没有key的时,它自己内部其实就是使用的index作为key,但好处就是清除了控制台的报错。

想象下,如果数据插入,删除或重新排序,则渲染数据项的顺序将随着时间的推移而变化。这使得index作为key会导致微妙而令人困惑的bug。

为什么 ? 因为用index作为key它是动态的(数组的删除、更新和排序,index对每个数据项来说作为key都是一直在变化的)。

这使得渲染时的key总是不匹配,导致每次都要重新创建所有组件DOM。这不仅会减慢速度,而且还会丢失列表项中的任何用户输入

三、如何正确的使用key

  • 在数组中key在每个数据项之间必须唯一。但是,它允许在不同的数组中,数据项key可以相同。
const a = [{key:0,val:a1},{key:1,val:a2}]

const b = [{key:0,val:b1},{key:1,val:b2}]
  • 我们得到一个要渲染的数组对象时,如果没有很好的key作为唯一条件,则应该在渲染前对数据处理好。

  • 如果是普通的数组,并且数据不会重新排序、新增和修改这种情况,我们是可以使用index作为索引的。

const array = {
 lines: [
   'apple',
   'pear',
   'banana'
 ]
};

export default function frust() {
 return (
   <>
     {array.lines.map((line, index) =>
       <p key={index}>
         {line}
       </p>
     )}
   </>
 );
}

  • 除了上述情况,不要在渲染的时候生成key比如indexindex作为key不稳定,破坏了key的用途。

  • 在最顶层的标签使用key

 export default function frust() {
  return (
    <>
      {array.lines.map((line, index) =>
          <div key={line.id}>
            //不应该在p中使用key
            <p>  
              {line}
            </p>
          </div>
      )}
    </>
  );
}

注意

如果把key当做prop传给子组件不能使用 key={line.id},这是错误的,正确的是keyItem={line.id}

 export default function frust() {
  return (
    <>
      {array.lines.map((line,) =>
        此时index不能传递到Category
          <Category key={line.id}>
            <p>  
              {line}
            </p>
        </Category>
      )}
    </>
  );
}

结尾

至此关于reactkey内容暂告一段落。