React

在Web开发中,要将更新的数据实时反映到UI上,就不可避免地需要对DOM进行操作,而复杂频繁的DOM操作通常是产生性能瓶颈的原因之一。为此,React引入了Virtual DOM机制。Virtual DOM实际上是在浏览器端用JavaScript实现的一套DOM API,它包括:

  • Virtual DOM模型
  • 生命周期的维护和管理
  • 性能高效的diff算法
  • Virtual DOM展示为原生DOM的Patch方法

基于React进行开发时,所有的DOM树都是在Virtual DOM的基础上构造的。React在Virtual DOM上实现了DOM diff算法,当数据更新时,会通过diff算法寻找到需要变更的DOM节点,并只对变化的部分进行实际的浏览器的DOM更新,而不是重新渲染整个DOM树。

Virtual DOM模型

ReactNode

  • ReactElement

    • ReactComponentElement
    • ReactDOMElement
  • ReactFragment
  • ReactText

创建React元素

通过JSX创建的虚拟元素最终会被编译成调用React的createElement方法

初始化组件入口

当使用React创建组件时,首先会调用instantiateReactComponent,这是初始化组件的入口函数,它通过判断node类型来区分不同组件的入口

文本组件

ReactDOMTextComponent

标签组件

ReactDOMComponent

自定义组件

ReactCompositeComponent

生命周期

React的主要思想是通过构建可复用组件来构建用户界面。所谓组件,就是有限状态机,通过状态渲染对应页面,每个组件组件都有自己的生命周期,它规定了组件和方法需要在哪个阶段改变和执行。

diff算法

diff算法会帮助我们计算出Virtual DOM中真正变化的部分,并只针对该部分进行原生DOM操作,而非重新渲染整个页面,从而保证了每次操作更新后页面的高效渲染。

传统diff算法

  • 计算一颗树形结构转换成另一棵树形结构的最少操作
  • 传统算法通过循环递归对节点进行一次对比,算法复杂度达到O(n³)

React对diff算法的改进

React结合DOM树的特点,对传统diff算法进行了改进,将其转换为O(n)复杂度的问题

React diff算法的三个策略
  • Web UI中DOM节点跨层级的操作较少(如果有,可以理解为删去一个节点,在另一层级插入新节点)
  • 拥有相同类的两个组件会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构
  • 对于同一层级的一组子节点,它们可以通过唯一的id进行区分
tree diff(上面的第一个策略)
  • 对树进行分层比较,两颗树只会对同一层次的节点进行比较
  • React只会简单地考虑同层级节点的位置变换,而对于不同层级的节点,只有创建和删除操作
  • 在开发组件时,保持稳定的DOM结构有助于性能的提升,建议不要进行DOM节点跨层级的操作
component diff(第二个策略)
  • 如果是同一类型的组件,则按照原策略继续比较Virtual DOM
  • 如果不是同一类型的组件,则将旧组件直接删除,在该位置重新创建新组件
  • 如果是同一类型的组件,有可能其Virtual DOM没有任何变化,如果我们能够明确知道这点,这可以利用shouldComponentUpdate()来判断组件是否需要进行diff算法分析
element diff(第三个策略)
  • 当节点处于同一层级时,diff算法提供了3中节点操作,分别为插入、移动、删除
  • 对于同一层级的同组子节点,需要添加唯一key进行区分,通过这种方法来解决相同节点位置变化的情况

React Patch方法

将diff算法计算出来的DOM差异队列更新到真实的DOM节点上,最终让浏览器能够渲染出更新的数据。

(未完待续...)

参考

深入浅出React


jhhfft
590 声望40 粉丝

Write the Code. Change the World.