笔记:React 中关于 key 的一点总结

栏目: IOS · Android · 发布时间: 6年前

内容简介:译:当您使用React时,您可以在单个时间点将该这里涉及到两个算法复杂度的问题,总而言之就是:react中的
When you use React, at a single point in time you can think of the render() function as creating a tree of React elements. On the next state or props update, that render() function will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree.

译:当您使用React时,您可以在单个时间点将该 render() 函数视为创建React元素树。在下一个状态或道具更新时,该 render() 函数将返回一个不同的React元素树。然后, React 需要弄清楚如何有效地更新UI以匹配最新的树。

这里涉及到两个算法复杂度的问题,总而言之就是:

key

key 是如何工作的?

react中的 key 属性是一个特殊的属性,它是出现 不是给开发者 用的(例如你为一个组件设置 key 之后不能获取组件的这个 key props), 而是给react自己用的

react利用 key 来识别组件,它是一种身份标识标识,就像我们的身份证用来辨识一个人一样。每个 key 对应一个组件,相同的 key react认为是同一个组件,这样后续相同的 key 对应组件都不会被创建。

笔记:React 中关于 key 的一点总结
this.state = {
 users: [{id:1,name: '张三'}, {id:2, name: '李四'}, {id: 2, name: "王五"}],
 ....//省略
}
render()
 return(
  <div>
    <h3>用户列表</h3>
    {this.state.users.map(u => <div key={u.id}>{u.id}:{u.name}</div>)}
  </div>
 )
);
复制代码

上面代码在 dom 渲染挂载后,用户列表只有张三和李四两个用户,王五并没有展示处理,主要是因为 react 根据 key 认为李四和王五是同一个组件,导致第一个被渲染,后续的会被丢弃掉。

key的值必须保证唯一且稳定

这样,有了 key 属性后,就可以与组件建立了一种对应关系, react 根据 key 来决定是销毁重新创建组件还是更新组件。

  • key相同,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新。

  • key 值不同,则react先销毁该组件(有状态组件的 componentWillUnmount 会执行),然后重新创建该组件(有状态组件的 constructorcomponentWillUnmount 都会执行)

笔记:React 中关于 key 的一点总结

还没完( 我再简单说两句 ),在项目开发中, key属性的使用场景最多的还是由数组动态创建的子组件的情况,需要为每个子组件添加唯一的key属性值

index 的使用

在list数组中,用 key 来标识数组创建子组件时,我的通常做法:

{this.state.data.map((v,idx) => <Item key={idx} v={v} />)}
// index 作为key方便快捷一步到位
<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>
复制代码

但是···

若涉及到数组的动态变更,例如数组新增元素、删除元素或者重新 排序 等,这时 index 作为 key 会导致展示错误的数据。

{this.state.data.map((v,idx) => <Item key={idx} v={v} />)}
// 开始时:['a','b','c']=>
<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>

// 数组重排 -> ['c','b','a'] =>
<ul>
    <li key="0">c <input type="text"/></li>
    <li key="1">b <input type="text"/></li>
    <li key="2">a <input type="text"/></li>
</ul>

复制代码

上面实例中在数组重新排序后, key 对应的实例都没有销毁,而是重新更新。具体更新过程我们拿 key=0 的元素来说明, 数组重新排序后:

  • 组件重新 render 得到新的虚拟 dom

  • 新老两个虚拟 dom 进行 diff ,新老版的都有 key=0 的组件, react 认为同一个组件,则只可能更新组件;

  • 然后比较其 children ,发现内容的文本内容不同(由a--->c),而 input 组件并没有变化,这时触发组件的 componentWillReceiveProps 方法,从而更新其子组件文本内容;

  • 因为组件的 childreninput 组件没有变化,其又与父组件传入的任 props 没有关联,所以 input 组件不会更新(即其 componentWillReceiveProps 方法不会被执行),导致用户输入的值不会变化。

这就是 index 作为 key 存在的问题, index 作为 key 是一种反模式, 不要轻易使用index作为key 。(若数组的内容只是作为纯展示,而不涉及到数组的动态变更,还是很推荐的。)

笔记:React 中关于 key 的一点总结

官网的两个demo:demo1,demo2, 大家可以去看看。

index 的替代

归根结底,使用 index 的问题在于两次渲染的 index 是相同的,导致 key 也是相同的,回到上面:point_up_2:的总结 : key相同,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新

这时候,如果保证每次的 key 不同,问题不就解决了么?

于是乎···

key={index +  Math.random()}
复制代码

一行神奇的代码就产生了。

能解决问题么?能!是最优的么?不是。

笔记:React 中关于 key 的一点总结

翻看官方文档 , 官方文档中明确指出 Don’t pass something like Math.random() to keys

key应该是稳定的,可预测的和独特的。不稳定的 key (如由其生成的key Math.random() )将导致许多组件实例和DOM节点被不必要地重新创建,这可能导致性能下降和子组件中的丢失状态。

所以,在不能使用 random 随机生成 key 时,我们可以像下面这样用一个全局的 localCounter 变量来添加稳定唯一的 key 值。

var localCounter = 1;
this.data.forEach(el=>{
    el.id = localCounter++;
});
//向数组中动态添加元素时,
function createUser(user) {
    return {
        ...user,
        id: localCounter++
    }
}
复制代码

所以,我最后的解决方案是全局定义一个变量: let ONE = 1; ,然后在组件中使用 key = {ONE++} 。这样 setSete() 的时候每次 key 都产生了变化,也一定程度上避免了 key 的不稳定性质。问题解决,收工。

笔记:React 中关于 key 的一点总结

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

30天自制操作系统

30天自制操作系统

[日] 川合秀实 / 周自恒、李黎明、曾祥江、张文旭 / 人民邮电出版社 / 2012-8 / 99.00元

自己编写一个操作系统,是许多程序员的梦想。也许有人曾经挑战过,但因为太难而放弃了。其实你错了,你的失败并不是因为编写操作系统太难,而是因为没有人告诉你那其实是一件很简单的事。那么,你想不想再挑战一次呢? 这是一本兼具趣味性、实用性与学习性的书籍。作者从计算机的构造、汇编语言、C语言开始解说,让你在实践中掌握算法。在这本书的指导下,从零编写所有代码,30天后就可以制作出一个具有窗口系统的32位......一起来看看 《30天自制操作系统》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具