阅读 90

重新学习 React (二) Diffing 算法

前几天面试问道 react 的相关知识,对我打击比较大,感觉对 react 认识非常肤浅,所以在这里重新梳理一下,想想之前没有仔细思考过的东西。

另外有说的不对的地方还请帮我指正一下,先谢谢各位啦。

目录索引:

背景

我们知道,React 执行 Render() 函数时,会生成一次虚拟 DOM,当组件再次更新时,会再生成一颗新的树,然后 React 会对比两棵树的异同,执行更新算法。React 通过如下方法比较 DOM 的异同,其复杂度为 O(n):

  • 两个不同类型的元素会产生出不同的树
  • 开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定

Diffing 算法

当对比两颗树时,React 首先比较两棵树的根节点。不同类型的根节点元素会有不同的形态。

比对不同类型的元素

当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树。举个例子,当一个元素从 <a> 变成 <img> 或者 DOM 节点被销毁,都会触发一个完整的重建流程。

比对同一类型的元素

当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。

如下所示,当更新 style 属性时,React 仅更新有所更变的属性,而 title 属性不会被修改。

<div className="before" title="stuff" />
<div className="after" title="stuff" />
复制代码

比对同类型的组件元素

当一个组件更新时,组件实例保持不变,这样 state 在跨越不同的渲染时保持一致。React 将更新该组件实例的 props 以跟最新的元素保持一致,并且调用该实例的 componentWillReceiveProps() 和 componentWillUpdate() 方法。

key

如果一个列表没有 key 值,一旦数组增加或者删除,react 就无法知道那些元素是不变的,那些的改变了的。但是当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素。以下例子在新增 key 之后使得之前的低效转换变得高效:

<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 知道只有带着 '2014' key 的元素是新元素,带着 '2015' 以及 '2016' key 的元素仅仅移动了。

结语

关于 key 值,一定要知道其作。自己在写代码的时候尽量不要采用 index 或者随机数作为 key,因为这样不但没有获得 react 优化算法的加持,而且会让自己的数据出现错乱。

关注下面的标签,发现更多相似文章
评论