React 中的diff 算法

虚拟DOM 和 Diff 算法

问题:我们知道state 更新组件的时候,只要state 变化就重新渲染视图,如果组件中只有一个DOM 元素需要更新时,也需要将整个组件内容重新渲染到页面中吗?

回答:不是,虚拟DOM 和 Diff 算法可以达到部分更新

虚拟DOM: 本质上是个 js 对象,用来描述页面UI (React 元素就是虚拟DOM)

执行过程

  • React组件配合 state 创建一个虚拟DOM树

  • 根据虚拟DOM树,生成一个真正的 DOM 树,再渲染到页面中

  • 当 state 或者 props 变化时,根据新的数据生成一个新的虚拟DOM树

  • 将新旧虚拟 DOM 树进行对比,通过diff算法找到新旧虚拟DOM的差异点,最后将差异点更新到页面上

React 中的diff 算法_第1张图片

diff算法

1、diff算法的作用

计算出Virtual DOM中真正变化的部分,并只针对该部分进行原生DOM操作,而非重新渲染整个页面。

2、React 中的diff算法

调和是指 将Virtual DOM树转换成Actual DOM树的最少操作的过程,而 diff算法是调和的具体实现。

3、diff 策略

  1. 策略一(tree diff): 按照树的层级进行比较叫做 tree diff,如果该节点不存在,则整个删除,不再继续比较

React 中的diff 算法_第2张图片
如果DOM节点出现了跨层级操作,diff会咋办呢?

diff只简单考虑同层级的节点位置变换,如果是跨层级的话,只有创建节点和删除节点的操作。

React 中的diff 算法_第3张图片
如上图所示,以A为根节点的整棵树会被重新创建,而不是移动,官方也建议不要进行DOM节点跨层级操作,可以通过CSS隐藏、显示节点,而不是真正地移除、添加DOM节点。

  1. 策略二(component diff): 每一层中组件的对比叫做 component diff
  • 同一类型的两个组件,按层级比较Virtual DOM树。

  • 同一类型的两个组件,组件A变化为组件B时,可能Virtual DOM没有任何变化,可以通过 shouldComponentUpdate() 来判断是否需要判断计算。

  • 不同类型的组件,将一个(将被改变的)组件判断为dirtycomponent(脏组件),从而替换整个组件的所有节点。

  1. 策略三(element diff):如果两个组件类型相同,则需要对比组件中的元素,叫做 element diff,
    diff提供三种节点操作:删除、插入、移动。

    插入:组件 C 不在集合(A,B)中,需要插入

    删除

    • 组件 D 在集合(A,B,D)中,但 D的节点已经更改,不能复用和更新,所以需要删除 旧的D ,再创建新的。
    • 组件D之前在集合(A,B,D)中,但集合变成新的集合(A,B)了,D 就需要被删除。

    移动:同一层级的同组子节点元素发生变化,对同一层级的同组子节点添加唯一key进行区分,从而移动。

虚拟DOM和Diff 算法代码演示

组件 render() 调用后,根据状态JSX 结构生成虚拟DOM对象

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {
  state = {
    number:0
  }
  handleClick=()=>{
    this.setState(()=>{
      return{
        number:Math.floor(Math.random() * 3)
      }
   
    })
  }
//render 方法调用并不意味着浏览器的重新渲染!!! (只会更新h1文本节点内容)
//render 方法调用仅仅说明要进行diff
   render(){
     const el = (
       <div>
         <h1>随机数:{this.state.number}</h1>
         
         <button onClick={this.handleClick}>重新生成</button>
       </div>
     )
     console.log(el);
     return el
   }
 }
ReactDOM.render(<App/>, document.getElementById('root'))

你可能感兴趣的:(React,react.js,javascript,前端)