React高级指南(八)【Reconciliation】
一致化处理(Reconciliation)React提供声明式API,因此在每次更新中你不需要关心具体的更改内容。这使得编写应用更加容易,但是这样使得你对React内部具体实现并不了解,这篇文章介绍了在React的”diffing”算法中我们所作出地决择,以使得组件的更新是可预测的并且可以适用于高性能应用。 动机当你使用React的时候,在任何时刻,你可以认为 目前存在大量通用的方法能够以最少的操作步骤将一个树转化成另外一棵树。然而,state of the art algorithms的时间复杂度为O(n3),其中n为树中的元素个数。 如果我们在React中展示1000个元素,那么每次更新都需要1百万次的比较,这样的代价过于昂贵。然而,React基于以下两个假设实现启发式算法,使得时间复杂度为O(n):
事实上,这些假设对于大部分实例都是有效的。 Diffing 算法当React比较(diffing)两棵树时,React首先比较两棵树的根元素。根据根元素的不同,行为也有所不同。 元素类型不相同无论什么时候,当树的根节点类型不同时,React将会销毁原先的树并重头构建新的树。从 当卸载原先的树时,之前的DOM节点将销毁。实例组件执行 树的根节点以下的任何组件都会被卸载(unmount),其状态(state)都会丢失。例如,当比较: <div>
<Counter />
</div>
<span>
<Counter />
</span>
DOM元素类型相同当React比较两个React DOM元素是相同类型时,React观察两者属性,保持底层DOM节点相同,并且仅更新已经改变的属性,例如: <div className="before" title="stuff" />
<div className="after" title="stuff" />
通过比较两个元素,React会仅修改底层DOM节点的 当更新 <div style={{color: 'red',fontWeight: 'bold'}} />
<div style={{color: 'green',fontWeight: 'bold'}} />
当React对两个元素进行转化的时候,仅会修改 在处理完当前DOM节点后,React会递归处理子节点。 相同类型的组件当一个组件更新的时候,组件实例保持不变,以便在渲染过程中保存state。React会更新组件实例的属性来匹配新的元素,并在元素实例上调用 接下来, 子元素递归当React递归DOM元素的子节点时,默认地在同一时刻迭代这两个子元素列表,并在有差异时生成一个变量。 例如,当给子元素末尾添加一个元素,在两棵树之间转化中性能就不错: <ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
React会比较 如果在开始处插入一个节点也是这样简单地实现,那么性能将会很差。例如,在下面两棵树的转化中性能就不佳。 <ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
如果React改变每一个元素,而不是知道应该保持 Keys为了解决这个问题,React支持 <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属性为 事实上,查找一个key属性并不困难。你所将要展示的组件一般都有唯一的ID,因此你的数据可以作为key的来源。 <li key={item.id}>{item.name}</li>
当情况不同时,你可以添加一个新的ID属性给你的model或者部分内容的hash值来作为key。key仅仅只需要在其兄弟节点中是唯一的,并非全局唯一。 作为最后一种方案,你可以将元素的下标作为key属性。如果元素永远不会被重新排序的情况下这样也是不错的,但是如果存在重新排序,性能将会很差。 折衷需要记住的是一致化算法(reconciliation algorithm)仅仅只是一个实现细节。React会在每个操作上重新渲染整个应用,最终的结果可能是相同的。我们经常细化启发式算法,以便优化性能。 在最近的实现中,你能确定子树会在兄弟节点中移动,但你不能确定它可以移动到别的地方去。算法会重新渲染整个树。 因为React依赖于启发式算法,如果下面的假设没有实现,性能将会大大的损失。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |