React
提供给我们声明式的API
以至于我们根本不需要关心React
内部到底做了什么,这让我们写代码变得轻松,但是我们还是非常有必要了解React
内部实现机制,这对我们自己开发一个公司框架以及深入学习React
是非常有帮助的。
这一篇博客就是深入的讲解
React
的更新机制也属于React的调解器知识点,打开你内心世界React
的大门,让我们见识见识diff
算法的魅力吧,骚年们!
1.算法魅力
之前将性能优化的时候已经提到过基本的更新流程,render
进行视图渲染,然后React
检查是否发生变化,发生了就更新。
有一些一般的算法以最小的代价更新一棵树为另外一棵树,即便是最好的算法它也是
pdf
详细进行了算法讲解,大家可以去看看,当然在React
高级教程中会进行讲解)
当我们在React
用前面那种算法的话,就单单
React
用一个种
这个启发式算法的使用基于以下两点:
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
中的数据