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 只会去修改节点的classNam e属性,而不会去更改其他的地方
当处理完这一层节点后,React 就会递归去处理它们的子节点
特提:处理类型相同的组件
当是比较类型相同的组件时,React 调用componentWillReceiveProps 和componentWillUpdate 函数进行处理(这两个函数后续会讲解),然后直接使用rende r函数,接着又是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 中的数据
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|