React 原理浅析 (虚拟DOM, diff)

·  阅读 696
React 原理浅析 (虚拟DOM, diff)
  • 什么是virtualDom
  • 什么是diff算法
  • key的作用

jsx是什么

我们先来看一段jsx代码

let add = (
    <div id = '1'>
        <p>abc</p>
    </div>
)
复制代码

最终会被编译为:

var app = React.createElement('div', {id: 'a'}, React.createElement("p", null, "abc"));
复制代码

jsx 代码会经过babel-loader 会解析为 React.createElement(...)嵌套对象。

React.createElement(...) 就是创建一个虚拟DOM结构。

ReactDom.render 将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理,事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM.

VirtualDom


vritualDom是什么

通过React.createElement(...)创建的一个javaScript对象,该对象描述了DOM树的结构,可以通过它生成一个真实的DOM。

虚拟DOM的组成

就是ReactElement对象树,我们的组件最终会被渲染成下面的虚拟DOM:

virtualDom.awebp

  • type: 元素的类型,可以是原生HTML类型(字符串),或者自定义组件(函数或class);
  • key: 组件的唯一标识;
  • ref: 用于访问原生DOM节点;
  • props: 传入组件的props, children是props的一个属性,它存储了当前组件的孩子节点,可以是数组(多个孩子节点)或对象(只有一个孩子节点);
  • self: (非生产环境)指定当前位于哪个组件实例;
  • _source: (非生产环境) 指定调试代码来自的文件(fileName)和代码行数(lineNumber);

为什么需要虚拟DOM

提高开发效率

"提升性能"

直接操作DOM是非常耗费性能的,这一点毋庸置疑。但是React使用virtualDOM也是无法避免操作DOM的。如果是首次渲染,virtualDOM不具有任何优势,甚至它要进行更多的计算,消耗更多的内存;

  • 那为什么我们还是需要虚拟DOM呢

优势在于React的Diff算法和批处理策略,React在页面更新之前,提前计算好如何更新和渲染DOM。 所以,更倾向于说,虚拟DOM帮助我们提高了开发效率,在重复渲染时它帮助我们计算如何更高效的更新,而不是它比DOM操作更快。

跨浏览器兼容

React 基于 virtualDOM自己实现了一套事件机制,自己模拟了事件冒泡和捕获的过程,采用了事件代理,批量更新等方法,抹平了各个浏览器的事件兼容性。

跨平台兼容

virtualDOM为React带来了跨平台渲染的能力,以React-native为例子,React根据virtualDOM画出相应平台的UI.

diff算法

React Diff会帮助我们计算出virtualDom中真正发生变化的部分,并且只针对该部分进行实际的DOM操作,而不是对整个页面进行重新渲染。

传统的diff算法

传统的diff算法是使用递归循环对节点进行依次对比,时间复杂度为O(n^3), 效率低下

React Diff算法策略

  1. 两个相同的组件产生类似的DOM结构,不同组件产生不同DOM结构
  2. 对于同一层次的一组子节点,它们可以通过唯一的id区分(key)

基于第一条策略:Diff算法只会对同层的节点进行比较。

diff.awebp

也就是说如果父节点不同,React将不会再去对比子节点,因为不同的组件DOM结构会不相同, 所以就没有必要再去对比子节点了。这也提高了对比的效率,把事件复杂度降低为O(n).

key值的重要性

使用React要注意的一点是,Key值必须是稳定的(不能使用Math.random去创建key), 可预测并且是唯一的,这里给我们性能优化提供了两个非常重要的依据:

  • 保持DOM结构的稳定性
  • 加唯一key值

React会根据key来决定是销毁重新创建组件还是更新组件,原则是:

  • key相同,组件有所变化,React会只更新组件对应变化的属性。
  • key不同,组件会销毁之前的组件,将整个组件重新渲染。
分类:
前端
标签:
分类:
前端
标签: