回想下,当我们在react开发中是不是经常写下面的代码
const data = [a, b, c];
<ul>{
data.map((item,index)=>{
return <li key={index}>item <input type="text"/></li>
})
}</ul>
当我们通过数组来动态渲染一批组件时,react要求我们必须为每一个组件添加一个唯一的key值,不然就会在控制台出现如下warning:warning.js:33 Warning: Each child in an array or iterator should have a unique "key" prop.
。
如果添加的key值有重复,那么重复的组件只会渲染出一个,并且react给出提示 :Child keys must be unique; when two children share a key, only the first child will be used.
添加key值需要遵循:
- 必需性
key值在react中的用途可大呢,diff时根据开发者添加的key来判断新旧组件是否为同一个组件,进而决定是执行insert、remove、move操作,而这将影响页面渲染的速度和性能。至于为什么key这么重要,控制台不是报错而是警告呢?因为你实在不加key的情况,react默认取遍历的index。 - 唯一性
key值只需要在同一次map中保证唯一。
react利用key来识别组件,它是一种身份标识标识,就像我们的身份证用来辨识一个人一样。每个key对应一个组件,相同的key react认为是同一个组件,这样后续相同的key对应组件都不会被创建。 - 稳定性
不要用index作为组件的key,index并不能唯一的标识一个组件。如果只是单纯的用作展示,到还可以。但若涉及到新增、删除元素或者重新排序时,就可能出现问题。有位大神举的例子可以很好的阐述这个问题,我就直接引用下
文章开头的例子,渲染出的结构如下
<ul>
<li key=0>a <input type="text"/></li>
<li key=1>b <input type="text"/></li>
<li key=2>c <input type="text"/></li>
</ul>
依次在三个input中输入1、2、3
增加一条数据
data = [g, a, b, c]
后,渲染结构如下
<ul>
<li key=0>g <input type="text"/></li>
<li key=1>a <input type="text"/></li>
<li key=2>b <input type="text"/></li>
<li key=3>c <input type="text"/></li>
</ul>
页面结果:与我们期望的结果并不一致,为什么input框内的值错位了呢
上面实例中在数组新增后,前三个key对应的实例都没有销毁,而是重新更新。具体更新过程我们拿key=0的元素来说明, 数组新增后:
- 组件重新render得到新的虚拟dom;
- 新老两个虚拟dom进行diff,新老版的都有
key=0
的组件,react认为同一个组件,则只可能更新组件; - 然后比较其children,发现内容的文本内容不同(由a--->c),而input组件并没有变化,这时触发组件的
componentWillReceiveProps
方法,从而更新其子组件文本内容; - 因为组件的children中input组件没有变化,其又与父组件传入的新
props
没有关联,所以input组件不会更新(即其componentWillReceiveProps
方法不会被执行),导致用户输入的值不会变化。
这就是index作为key存在的问题,所以不要使用index作为key。
也不能用Math.random()生成key值,这样虽然能保证key值的唯一性,但是会导致数组每次改变时,组件都重新销毁并新建,耗费性能。还可能导致一些意想不到的问题。