- 什么是
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:
- 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算法策略
- 两个相同的组件产生类似的DOM结构,不同组件产生不同DOM结构
- 对于同一层次的一组子节点,它们可以通过唯一的id区分(key)
基于第一条策略:Diff算法只会对同层的节点进行比较。
也就是说如果父节点不同,React将不会再去对比子节点,因为不同的组件DOM结构会不相同, 所以就没有必要再去对比子节点了。这也提高了对比的效率,把事件复杂度降低为O(n).
key值的重要性
使用React要注意的一点是,Key值必须是稳定的(不能使用Math.random去创建key), 可预测并且是唯一的,这里给我们性能优化提供了两个非常重要的依据:
- 保持DOM结构的稳定性
- 加唯一key值 React会根据key来决定是销毁重新创建组件还是更新组件,原则是:
- key相同,组件有所变化,React会只更新组件对应变化的属性。
- key不同,组件会销毁之前的组件,将整个组件重新渲染。