内容简介:译:当您使用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 对应组件都不会被创建。
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会执行),然后重新创建该组件(有状态组件的constructor和componentWillUnmount都会执行)
还没完(
我再简单说两句
),在项目开发中, 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方法,从而更新其子组件文本内容; -
因为组件的
children中input组件没有变化,其又与父组件传入的任props没有关联,所以input组件不会更新(即其componentWillReceiveProps方法不会被执行),导致用户输入的值不会变化。
这就是 index 作为 key 存在的问题, index 作为 key 是一种反模式, 不要轻易使用index作为key 。(若数组的内容只是作为纯展示,而不涉及到数组的动态变更,还是很推荐的。)
官网的两个demo:demo1,demo2, 大家可以去看看。
index 的替代
归根结底,使用 index 的问题在于两次渲染的 index 是相同的,导致 key 也是相同的,回到上面:point_up_2:的总结 : key相同,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新 。
这时候,如果保证每次的 key 不同,问题不就解决了么?
于是乎···
key={index + Math.random()}
复制代码
一行神奇的代码就产生了。
能解决问题么?能!是最优的么?不是。
翻看官方文档 , 官方文档中明确指出 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 的不稳定性质。问题解决,收工。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hacking Growth
Sean Ellis、Morgan Brown / Crown Business / 2017-4-25 / USD 29.00
The definitive playbook by the pioneers of Growth Hacking, one of the hottest business methodologies in Silicon Valley and beyond. It seems hard to believe today, but there was a time when Airbnb w......一起来看看 《Hacking Growth》 这本书的介绍吧!
html转js在线工具
html转js在线工具
HEX HSV 转换工具
HEX HSV 互换工具