React之虚拟DOM和diff算法

createEmement 创建组件

createElement 是另一种创建 react 元素的方法,但是相对麻烦,并且难于维护所以了解即可

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

// 参数1: 标签名
// 参数2: 标签属性
// 参数3: 标签内部的子节点
const jsx = React.createElement(
  'div',
  {
    
     className: 'top', title: 'hello' },
  '你好啊'
)
// <div class="top" title="hello">你好啊</div>
ReactDOM.render(jsx, document.querySelector('#app'))

JSX转换过程

  • JSX 是 createElement() 方法的语法糖 (语法糖:更加直观、简洁、友好)
  • JSX 语法会被 @babel/preset-react插件编译为 createElement 方法
    △JSX 对程序员更方便直观、createElement方法运行起来更方便
  • createElement 又会被转化为 React元素,React元素是一个对象,能够描述UI结构
    在这里插入图片描述
    在这里插入图片描述
// 核心
{
    
    
    type: 'div',
    props: [
         {
    
    className: 'top'},
         {
    
    children: 'Hello JSX'}
    ]
}

虚拟DOM

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

在这里插入图片描述
创建时:

  • React组件配合 state 创建一个虚拟DOM树
  • 根据虚拟DOM树,生成一个真正的 DOM 树,再渲染到页面中

更新时:

  • 当 state 或者 props 变化时,生成一个新的虚拟DOM树
  • 新旧虚拟 DOM 树进行对比(diff算法),找到新旧虚拟DOM的差异点
  • 将差异点更新到页面上

diff算法

  • tree diff: 按照树的层级进行比较叫做 tree diff,如果该节点不存在,则整个删除,不再继续比较
  • component diff: 每一层中组件的对比叫做 component diff
    △ 如果前后组件类型相同,暂时不需要更新
    △ 如果前后组件类型不同,则需要更新
  • element diff:如果两个组件类型相同,则需要对比组件中的元素,叫做 element diff
    △ 如果元素不同,则需要更新
    △ 如果元素相同,则不需要更新
    在这里插入图片描述

递归实现diff算法

实现思路:

  • 按照面向过程的方式来写代码
  • 当发现有雷同代码时,拆分观察,找异同
  • 规整代码

1) 按照面向过程的方式编写代码

// 声明一个空对象,用来保存找出的不同节点
var result = {
    
    }

// 遍历新树
for (var key in newTree) {
    
    

  if (typeof newTree[key] !== 'object') {
    
    

    if (newTree[key] !== oldTree[key]) {
    
    

      result[key] = newTree[key]
    }

  } else if (typeof newTree[key] === 'object') {
    
    

    result[key] = {
    
    }
    for (var k in newTree[key]) {
    
    
      if (typeof newTree[key][k] !== 'object') {
    
    
        if (newTree[key][k] !== oldTree[key][k]) {
    
    
          result[key][k] = newTree[key][k]
        }
      }
    }
    let tmpKeyArr = Object.keys(result[key])
    tmpKeyArr.length == 0 ? delete result[key] : ''
  }
}

console.log(result)

2)规整代码,封装函数,进行自调
注意: 内层函数调用时传入的参数

function diff (newNode, oldNode) {
    
    
  var result = {
    
    }

  for (var key in newNode) {
    
    
    if (typeof newNode[key] !== 'object') {
    
    
      if (newNode[key] !== oldNode[key]) {
    
    
        result[key] = newNode[key]
      }
    } else if (typeof newNode[key] === 'object') {
    
    
      result[key] = diff(newNode[key], oldNode[key])
      let tmpKeyArr = Object.keys(result[key])
      tmpKeyArr.length == 0 ? delete result[key] : ''
    }
  }

  return result
}

var res = diff(newTree, oldTree)
console.log(res)

Object.keys(obj): 获取obj对象的所有属性,并保存到一个数组中

let arr = Object.keys({a:'Hello', b:'World'}) ; arr = ['a', 'b']

delete Obj.a; 删除 obj 对象中的 a 属性

猜你喜欢

转载自blog.csdn.net/PILIpilipala/article/details/113338481