React中的diff算法

diff算法

一.前言

在React更新props或state时,会调用React中的render方法重新渲染一颗DOM树,React需要基于旧的DOM树和新的DOM树之间的差别来更新UI界面。
如果一棵树参考另外一棵树进行完全比较更新,那么即使是最先进的算法,该算法的复杂程度为 O(n^3 ),其中 n 是树中元素的数量。如果在 React 中使用了该算法,那么展示 1000 个元素所需要执行的计算量将在十亿的量级范围。这个开销实在是太过高昂。
React的渲染流程:
在这里插入图片描述

React的更新过程:
在这里插入图片描述

二.Diffing 算法

1.React在它的基础上优化出了一种O(n)的算法:
1.1.只进行同层节点的比较,不会跨节点进行比较
1.2.两个不同类型的元素会产生不同类型的树
1.3.开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定;
2.不同情况下的不同操作
2.1.对比不同类型的元素

当节点为不同类型的元素时,React会拆卸原有的树并且建立起新的树。
例如:

<!-- span元素  旧树-->
    <span>
        <button>按钮</button>
    </span>
<!-- div元素  新树-->
    <div>
        <button>按钮</button>
    </div>

如果这两颗DOM树进行比较,当比较当span元素和div元素时产生差异,React就会销毁span内的所有内容,替换为div元素的内容,不会进行子元素button的比较。

2.2.对比同一类型的元素

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

<div className="before" title="stud" />

<div className="after" title="stud" />

当对比这两个React元素时只修改它的className属性。当处理完此节点后,会继续进行子节点的递归。

2.3.对子节点进行递归

在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个 mutation。
在子元素列表末尾新增元素时,更新开销比较小。比如:

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

React 会先匹配两个<li>first</li> 对应的树,然后匹配第二个元素 <li>second</li> 对应的树,最后插入第三个元素的 <li>third</li> 树。

如果只是简单的将新增元素插入到表头,那么更新开销会比较大。比如:

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

React 不会意识到应该保留 <li>Duke</li><li>Villanova</li>,而是会重建每一个子元素 。这种情况会带来性能问题。

2.4.Keys的优化

为了解决2.3的问题,React 支持 key 属性。当子元素拥有 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 的元素仅仅移动了。

Keys选择注意事项:
1.key应该是唯一的;
2.key不要使用随机数(随机数在下一次render时,会重新生成一个数字);
3.使用index下标作为key,对性能是没有优化的;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值