一个页面其实就相当于是一颗dom树,里面有很多它的子节点,然后你每次去操作一个事件,它都会生成一个虚拟dom,它会跟上一个虚拟dom进行比对,这里运用的算法叫做diff算法,当它找到需要改变的组件的时候,就会让他重新渲染,因为在html中,dom树的重新渲染它是需要花费很长时间的

前提

在任意一个时刻,react中的render创建一颗元素树(element tree),当一个状态(state)变迁或者属性(props)更新, render将会返回一颗不同的元素树。react接下来将会计算出如何高效的根据最新的元素树更新UI。

react的更新算法,基于以下假设:

  1. 两个不同类型(type)的元素产出不同树。
  2. 开发者可以通过为子元素添加key属性,标示该元素在不同render之间是保持稳定不变的。

算法

比较两棵树的时候,react首先比较两棵树的根节点,会有如下几种情况:

不同类型的元素

销毁原来的树,创建新树。

销毁时,原来的Dom节点会被删除,component instance触发componentWillUnmount事件,创建新树时,新的Dom节点会插入到Dom树中, component instance会先后触发componentWillMount、componentDidMount。

根节点下的其他组件也会unmounted。例如:

<div>
<Counter />
</div> <span>
<Counter />
</span>

将会删除Counter,同时remount一个新的Counter。

相同类型的Dom元素

此时react检查两个Dom元素的属性,仅仅更新改变的属性,但是底层Dom节点是不变的。例如:

<div className="before" title="stuff" />
<div className="after" title="stuff" />

此时仅仅会更改底层Dom节点的className属性。

相同类型的Component元素

当一个组件更新时,组件实例保持不变,所以它的状态得以在不同render之间保持。react用新的元素(Element)更新底层组件实例的属性(props), 并且调用实例的componentWillReceiveProps和componentWillUpdate事件方法。

然后调用render。然后这个diff算法会根据之前的结果(prevRenderedElement)与现在的结果(nextRenderedElement)递归调用。

关于性能

当在Dom节点的children上递归调用的时候,默认的情况React仅仅同时迭代两棵树,当预见不同的时候就产生一个改变。 这对于如下情况,没有问题:

<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>

它会修改1、2两个li的text,然后插入一个li,这显然不是我们想要的,我们当然希望仅仅插入一个节点就可以了。 react需要找到一种方式,让我们在两次render之间,可以通过保持一些不变的东西,让他通过这个值去对比。

react通过key属性来表示。当children拥有keys的时候,react使用这些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就知道拿key值相同的进行比较,如此以来,发现仅仅添加了一个元素,就解决了我们的性能问题。

key的取值

我们需要保证key值在兄弟节点中是唯一的。通常按照如下步骤去选择key:

  1. model的id
  2. 添加一个唯一的id到model上
  3. 使用index(如果不reorder的话)

性能原则

因为react的diff算法基于的那两个假设,如果你的程序不遵从它或者偏离它,就可能出现性能问题。

  1. 此算法针对不同类型的component,会remount。所以当你发现两个component拥有极其类似的输出时,公用他们(只有一个类型)。
  2. key应该稳定(stable)、可预测(predicable)、唯一(unique)。不稳定的key会导致许多组件实例与Dom节点重复创建。

https://www.zhihu.com/question/29504639------如何理解虚拟dom

react性能调谐与diff算法的更多相关文章

  1. 从React渲染流程分析Diff算法

    1.什么是虚拟DOM 在React中,render执行的结果得到的并不是真正的DOM节点,结果仅仅是轻量级的JavaScript对象,我们称之为virtual DOM. 简单的说,其实所谓的virtu ...

  2. 【React自制全家桶】二、分析React的虚拟DOM和Diff算法

    一.React如何更新DOM内容: 1.  获取state 数据 2.  获取JSX模版 3.  通过数据 +模版结合,生成真实的DOM, 来显示,以下行代码为例(简称代码1) <div id= ...

  3. 深入理解React:diff 算法

    目录 序言 React 的核心思想 传统 diff 算法 React diff 两个假设 三个策略 diff 具体优化 tree diff component diff element diff 小结 ...

  4. 对React性能优化的研究-----------------引用

    JSX的背后 这个过程一般在前端会称为“转译”,但其实“汇编”将是一个更精确的术语. React开发人员敦促你在编写组件时使用一种称为JSX的语法,混合了HTML和JavaScript.但浏览器对JS ...

  5. React Diff算法

    Web界面由DOM树来构成,当其中某一部分发生变化时,其实就是对应的某个DOM节点发生了变化.在React中,构建UI界面的思路是由当前状态决定界面.前后两个状态就对应两套界面,然后由React来比较 ...

  6. React——diff算法

    react的diff算法基于两个假设: 1.不同类型的元素会产生不同的树 2.通过设置key,开发者能够提示那些子组件是稳定的 diff算法 当比较两个树时,react首先会比较两个根节点,接下来具体 ...

  7. 虚拟DOM和react中的diff算法总结

    https://blog.csdn.net/qq_26708777/article/details/78107577 一.虚拟DOM 1.什么是虚拟DOM及原理        把真实DOM树,变成js ...

  8. react虚拟dom diff算法

    react虚拟dom:依据diff算法 前端:更新状态.更新视图:所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性 刻不容缓 因为:Dom渲染慢,而JS解析编译相对非常非常非常快! ...

  9. React Diff 算法

    React介绍 React是Facebook开发的一款JS库,用于构建用户界面的类库. 它采用声明式范例,可以传递声明代码,最大限度地减少与DOM的交互. 特点: 声明式设计:React采用声明范式, ...

随机推荐

  1. noip模拟赛 c

    分析:一道比较难的爆搜题.首先要把9个块的信息存下来,记录每个块上下左右位置的颜色,然后记录每一排每一列能否操作,之后就是bfs了.在bfs的时候用一个数记录状态,第i位表示原来的第i个块现在在哪个位 ...

  2. 清北学堂模拟赛d7t1 消失的数字

    题目描述 现在,我的手上有 n 个数字,分别是 a1; a2; a3; :::; an.我现在需要删除其中的 k 个数字.当然我不希望随随便便删除,我希望删除 k个数字之后,剩下的 n - k 个数中 ...

  3. 火星人 2004年NOIP全国联赛普及组

    题目描述 Description 人类终于登上了火星的土地并且见到了神秘的火星人.人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法.这种交流方法是这样的,首先,火星人把一个 ...

  4. asp.net--解决上传文件大小限制

    原文地址 第一种方法,主要适用于IIS6.0版本 一.修改配置Web.Config文件中的httpRuntime节点 对于asp.net,默认只允许上传4M文件,增加如下配置,一般可以自定义最大文件大 ...

  5. Java中处理线程同步

    引自:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8295527和http://m.blog.csdn.net/blog/undoner/1 ...

  6. Application Framework层介绍

    http://write.blog.csdn.net/postedithttp://write.blog.csdn.net/postedithttp://write.blog.csdn.net/pos ...

  7. 一个基于cocos2d-x 3.0和Box2d的demo小程序

    p图demo小应用.想怎么p就怎么p 本文參考于http://blog.csdn.net/xiaominghimi/article/details/6776096和http://www.cnblogs ...

  8. 1215-Cannot add foreign key constraint

    1.错误描写叙述 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/ ...

  9. C++重载运算符简单总结

    当运算符作用于类类型的运算对象时,可以通过运算符重载重新定义该运算符的含义.明智的使用运算符重载能令我们的程序更易于编写和阅读. 一.基本概念 什么是运算符重载?重载的运算符是具有特殊名字的函数:它们 ...

  10. string[][]和string[,] 以及 int[][]和int[,]

    string[][]和string[,] http://www.codewars.com/kata/56f3a1e899b386da78000732/train/csharp Write a func ...