所以在每次更新的时候,React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI,如果一棵树参考另外一棵树进行完全比较更新,那么即使是最先进的算法,该算法的复杂程度为 O(n3),其中 n 是树中元素的数量,如果在React中使用了该算法,那么展示1000个元素所需要执行的计算量将在十亿的量级范围,这个开销太过昂贵了,React的更新性能会变得非常低效;于是React对这个算法进行了优化,将其优化成了O(n),这也就是传说中的diff算法,
diff 算法做了三处优化
<a>
变成<img>
,从<Article>
变成<Comment>
,或从<Button>
变成<div>
都会触发一个完整的重建流程<div>
<Comment />
</div>
<span>
<Comment />
</span>
<div className="before" title="stu" />
<div className="after" title="stu" />
<div style={{color="red",fontWeight:"bold"}} />
<div style={{color="green",fontWeight:"bold"}} />
<li>
星际穿越</li>
和<li>
盗梦空间</li>
的不变;这种低效的比较方式会带来一定的性能问题,所以就得使用key来优化后面插一条数据
<ul>
<li>星际穿越</li>
<li>盗梦空间</li>
</ul>
<ul>
<li>星际穿越</li>
<li>盗梦空间</li>
<li>大话西游</li>
</ul>
前面插一条数据
<ul>
<li>星际穿越</li>
<li>盗梦空间</li>
</ul>
<ul>
<li>大话西游</li>
<li>星际穿越</li>
<li>盗梦空间</li>
</ul>
参考 前端进阶面试题详细解答
要切记,在 diff 算法中,可以通过 key 来指定哪些节点在不同的渲染下保持稳定,并且要保证 key 是唯一的,不要使用随机数(随机数在下一次render时,会重新生成一个数字),也不能使用index,这都对性能是没有优化的
import React, { Component } from "react";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
movies: ["星际穿越", "盗梦空间"],
};
}
render() {
return (
<div>
<h2>电影列表</h2>
<ul>
{this.state.movies.map((item, index) => { return <li key={item}>{item}</li>; })} </ul>
<button onClick={(e) => this.insertMovie()}>添加电影</button>
</div>
);
}
insertMovie() {
this.setState({
movies: ["大话西游", ...this.state.movies],
});
}
}
代码解析:在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个mutation。如果在movies后面添加数据,前面两个比较是完全相同的,所以不会产生mutation;最后一个比较,产生一个mutation,将其插入到新的DOM树中即可;
如果在movies前面添加数据,React会对每一个子元素产生一个mutation,而不是保持 <li>
星际穿越</li>
和<li>
盗梦空间</li>
的不变,这种低效的比较方式会带来一定的性能问题,
当子元素(这里的li)拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素:
在下面这种场景下,key为"星际穿越"和"盗梦空间"的元素仅仅进行位移,不需要进行任何的修改; 将key为"大话西游"的元素插入到最前面的位置即可;
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。