|
React提供给我们声明式的API以至于我们根本不需要关心React内部到底做了什么,这让我们写代码变得轻松,但是我们还是非常有必要了解React内部实现机制,这对我们自己开发一个公司框架以及深入学习React是非常有帮助的。
这一篇博客就是深入的讲解React的更新机制也属于React的调解器知识点,打开你内心世界React的大门,让我们见识见识diff算法的魅力吧,骚年们!
1.算法魅力
之前将性能优化的时候已经提到过基本的更新流程,render进行视图渲染,然后React检查是否发生变化,发生了就更新。
有一些一般的算法以最小的代价更新一棵树为另外一棵树,即便是最好的算法它也是
O(n3)
的时间复杂度,
n
为树上的元素。(虽然个人并不知道它说的是什么算法啊,也不知道是怎么实现的,但是官网中有pdf详细进行了算法讲解,大家可以去看看,当然在React高级教程中会进行讲解)
[
这里说的算法只是说以最小的更新节点个数来定义的,也就是说上面描述的算法求解的是将一棵树变为另外一棵树最少需要更改多少个节点,时间负责度是那么多,实际应用中,我们不仅仅只是考虑以更新最好的节点来评判的,至少React的diff算法处理这个问题上就不是。
]
当我们在React用前面那种算法的话,就单单
1000
个元素都需要
O(10003)
的复杂度,还玩个毛线。这种效率实在是太低,代价昂贵,所以React用一个种
O(n)
的启发式算法来进行处理。
这个启发式算法的使用基于以下两点:
只要两个元素类型不同就会构造出不同的树
开发者可以会给每一个元素标记一个特殊的哈希属性
2.Diff算法
类型不同
在比较两颗树时,React首先比较这两颗树的根节点,至于判断不同就是判断他们的相应的状态和数据了
如果两个元素的类型不同的话,React会抛弃旧的树,构造新的树,比如说从<a>变到了<img>,<article>变到了<comment>,<button>变到了<div>,这些变化都会造成一个全新的树的构建,记住是以当前节点为根,完全重新建立,而不是单单更新根节点。
当摧毁旧树时,组件会调用componentWillUnmount()进行摧毁自身,当建立新的输时,会调用componentWillMount()处理,接着就是componentDidMount()处理,这里注意componentWillUnmount和componentWillMount的区别
这种更新方式会导致子树的所有节点状态摧毁,重新进行建立
<div>
<Counter />
</div>
<span>
<Counter />
</span>
类型相同
当类型相同时,React会看他们的属性,然后更新要更改的属性
<div className="before" title="stuff" />
<div className="after" title="stuff" />
这样,React只会去修改节点的className属性,而不会去更改其他的地方
当处理完这一层节点后,React就会递归去处理它们的子节点
特提:处理类型相同的组件
当是比较类型相同的组件时,React调用componentWillReceiveProps和componentWillUpdate函数进行处理(这两个函数后续会讲解),然后直接使用render函数,接着又是diff算法处理
3.对于列表孩子的处理
每当他们的父亲节点不同时,React就会处理出孩子列表,然后进行更新。
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
当时如果我们只是在孩子节点后面直接插入一个<li>chird</li>,它只会直接处理。 可是请看下面例子
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
这会更新所有的孩子节点,效率就比较低了
4.keys优化
为了解决3最后更新所有孩子节点的问题,React就提供了一个key属性,这个属性,之前将列表的时候就说过了,维护一个key比维护一个li标签更好。
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
这样React直接就知道key=2014是一个新的元素,而key=2015和key=2016则会往后移。
这其中的key要是唯一的,你可以是对象自己提供的,也可以用数组的索引,优劣在列表章节已经说了。
5.权衡
了解算法的实现是非常重要的,这样我们就可以更加深入的了解React处理的每一个细节,从而可以去优化性能.
当然,处理事件的时候一般会遇到这么两个问题
如果两者相似,应该作为不同处理,构造出不同的树
key值要具有唯一性,否则会造成子组件的丢失
这两个就是上面说的启发式处理的前提条件。
下一篇将讲React中的数据
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|