React介绍

React是Facebook开发的一款JS库,用于构建用户界面的类库。

它采用声明式范例,可以传递声明代码,最大限度地减少与DOM的交互。

特点:

  1. 声明式设计:React采用声明范式,你可以轻松描述你的应用
  2. 高效:React通过对DOM的模拟表现,最大限度地较少与DOM的交互。
  3. 灵活:React可以与你所知道的库或框架很好地工作。

在Web开发中,我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因

React为此引入了虚拟DOM(Virtual DOM)的机制:

在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个虚拟DOM树,然后React将当前整个虚拟DOM树和上一次的虚拟DOM树进行对比,得到虚拟DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。

React Diff 算法

虚拟DOM作为React的一大核心技术,了解其实现原理对于灵活应用有着很大帮助。

Javascript 虚拟DOM对象

在我们项目中申明一个组件是这样的:

react.createElement('div', null, [
// 创建一个img
react.createElement('img', { src: "avatar.png", class: "profile" }),
// 或者
react.createElement('h1', null, [[user.firstName, user.lastName].join(' ')])
]);

最后,React都会转换成类似这样的基本对象:

{
tagName: 'div',
// 节点包含的属性
properties: {
style: {
color: '#fff'
}
},
// 子节点
children: [],
// 节点的唯一标识
key: 1
}

Javascript DOM节点树

然后,React把Javascript DOM模对象 转换成 Javascript DOM节点树:

function create(vds, parent) {
!Array.isArray(vds) && (vds = [vds]);
// 如果没有父元素则创建个fragment来当父元素
parent = parent || document.createDocumentFragment();
var node;
vds.forEach(function (vd) {
// 如果是文字节点
if (isText(vd)) {
// 创建文字节点
node = document.createTextNode(vd.text);
} else {
// 创建元素
node = document.createElement(vd.tag);
}
// 将元素塞入父容器
parent.appendChild(node);
// 看看有没有子VNode,有孩子则处理孩子VNode
vd.children && vd.children.length &&
create(vd.children, node);
// 看看有没有属性,有则处理属性
vd.properties &&
setProps({ style: {} }, vd.properties, node);
});
return parent;
}

Diff Algorithm

现在我们得到的是Javascript 实现的虚拟DOM树,在一个事件循环中,当state或者preps变化时,React会创建一个新的虚拟DOM树,最后进行差异渲染。

diff(previous:VTree, current:VTree) -> PatchObject

React分三种情景:

a. 分层对比

React 仅仅是尝试把树按照层级分解. 这彻底简化了复杂度, 而且也不会失去很多, 因为 Web 应用很少有 component 移动到树的另一个层级去。它们大部分只是在相邻的子节点之间移动。

b. 基于key匹配

Keys是一个VNode的唯一识别,用于对两个不同的VTree中的VNode做匹配的。通过key锁定某个组件后,React就可以直接对比这两个差异DOM节点树,复杂度为O(n)。

所以这里有个性能优化的技巧。假设你有一个key组件,他的key属性为foo,后续又将它改为bar,那么React就会掉过DOM diff,同时完全弃置div所有自元素,从头渲染。在渲染大型子树以避免diff计算时,这样的设计很有用,因为我们知道这种计算就是在浪费时间。

c. 基于自定义元素做优化

React提供自定义元素,所以匹配很简单。React 只会匹配相同 class 的 component。

比如, 如果有个<Header><ExampleBlock>替换掉了,

React 会删除掉 header 再创建一个example block。我们不需要化宝贵的时间去匹配两个不大可能有相似之处的 component。

结束

React在你调用 component 的 setState 方法的时候, 将其标记为 dirty,到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制。每次调用 setState 会重新计算整个子树.如果你想要提高性能, 尽量少调用 setState。

最后, 你还有可能去掉一些子树的重新渲染,如果你在 component 上实现function shouldComponentUpdate(nextProps, nextState) 的话,你根据 component 的前一个和下一个 props/state,告诉 React 这个 component 没有更新, 也不需要重新绘制。

React Diff 算法的更多相关文章

  1. react diff算法浅析

    diff算法作为Virtual DOM的加速器,其算法的改进优化是React整个界面渲染的基础和性能的保障,同时也是React源码中最神秘的,最不可思议的部分 1.传统diff算法计算一棵树形结构转换 ...

  2. React Diff算法

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

  3. React——diff算法

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

  4. React Diff算法一览

    前言 diff算法一直是React系统最核心的部分,并且由于演化自传统diff,使得比较方式从O(n^3)降级到O(n),然后又改成了链表方式,可谓是变化万千. 传统Diff算法 传统diff算法需要 ...

  5. React基础(Diff算法,属性和状态)

    1.React的背景原理 (1)React Diff算法流程 (2)React虚拟DOM机制 React引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DO ...

  6. ReactiveNative学习之Diff算法

    React 源码剖析系列 - 不可思议的 react diff深入浅出React(四):虚拟DOM Diff算法解析React diff 算法总结链接引用的文章React出于性能的考虑,为了避免频繁操 ...

  7. React 源码剖析系列 - 不可思议的 react diff

      简单点的重复利用已有的dom和其他REACT性能快的原理. key的作用和虚拟节点 目前,前端领域中 React 势头正盛,使用者众多却少有能够深入剖析内部实现机制和原理. 本系列文章希望通过剖析 ...

  8. 直接操作DOM一定比虚拟DOM操作耗时,diff算法,key值,虚拟 DOM的定义

    直接操作DOM一定比虚拟DOM操作耗时吗? 或者一次直接DOM操作一定比一次虚拟DOM操作耗时吗? 1)虚拟DOM的本质就是一个JS对象,虚拟DOM减少了真实DOM的操作,当修改数据的时候,就是修改虚 ...

  9. diff算法深入一下?

    文章转自豆皮范儿-diff算法深入一下 一.前言 有同学问:能否详细说一下 diff 算法. 简单说:diff 算法是一种优化手段,将前后两个模块进行差异化比较,修补(更新)差异的过程叫做 patch ...

随机推荐

  1. centos shell脚本编程2 if 判断 case判断 shell脚本中的循环 for while shell中的函数 break continue test 命令 第三十六节课

    centos  shell脚本编程2 if 判断  case判断   shell脚本中的循环  for   while   shell中的函数  break  continue  test 命令   ...

  2. HTML5-Canvas 图形变换+状态保存

    1. 图形变换 canvas是基于状态绘制图形的.故此一般情况下,canvas的绘制的图形路径和状态时分离的. function drawShape(ctx){ // 绘制路径 shapePath(c ...

  3. Grid Search学习

    转自:https://www.cnblogs.com/ysugyl/p/8711205.html Grid Search:一种调参手段:穷举搜索:在所有候选的参数选择中,通过循环遍历,尝试每一种可能性 ...

  4. SpringData_JpaSpecificationExecutor接口

    不属于Repository体系,实现一组 JPA Criteria 查询相关的方法 Specification:封装 JPA Criteria 查询条件.通常使用匿名内部类的方式来创建该接口的对象 / ...

  5. 【转载】open-falcon部署

    运维监控系统之Open-Falcon   一.Open-Falcon介绍 1.监控系统,可以从运营级别(基本配置即可),以及应用级别(二次开发,通过端口进行日志上报),对服务器.操作系统.中间件.应用 ...

  6. ipod不识别命令

    root@mx6q:~# history 0 sync 1 reboot 2 cd /usr/app/ 3 ls 4 cd extend-sysfs/ 5 ls 6 cd etc/ 7 ls 8 cd ...

  7. double、float等多字节数据处理

    一.常规的多字节: 有2,4,8字节 float和double是具有自身算法的数据类型,和其他整型不一样[整型数据,可以直接通过移位来进行计算值的大小,float和double不行] 值 = 尾数x ...

  8. 防止putty的鼠标右键错误粘贴

    一.环境 发行版:Ubuntu 18.04.1 LTS 代号:bionic 内核版本:4.15.0-30-generic 二.背景 每次从putty复制时,会单击鼠标右击,以便复制出终端的内容,但是一 ...

  9. CSS设置文本末行显示省略号...

     首先设置文本标签或文字所在标签的宽度   最主要是以下三点:        ①white-space:nowrap;如果是中文需要设置行末不断行       ②overflow:hidden;设置控 ...

  10. BZOJ 1833 【ZJOI2010】 数字计数

    题目链接:数字计数 没啥好说的,裸裸的数位\(dp\). 先枚举当前是算数字\(x\)出现的次数,设\(f_{i,j}\)表示从高位往低位\(dp\),\(dp\)完了前\(i\)位之后\(x\)出现 ...