后端程序员入门react笔记——react的diff算法(三)

diffing算法

虚拟dom

我们知道,react里面操作的都是虚拟dom,最后经过render渲染为真正的dom,那么为什么要提出虚拟dom这个概念呢?其实就是将逻辑和视图区分开,react的虚拟dom,就相当于mvc的c,将数据逻辑和真正的dom区分开,我们知道,对于前端来说dom操作是非常昂贵的,性能消耗最大的就是dom操作。而virtual dom减少了对dom的操作,,不仅避免了资源浪费,而且页面的构建也得到了很大的提升。

为什么要diff

前面我们说了,应避免过多的操作dom,那么diff就是解决了这种问题。我们知道,react在状态发生变化的时候,会批量更新dom,生成新的UI,但是难道state的某一个值发生变化就要导致整个dom重新渲染吗?这明显是不科学的,为了解决这种问题,react提出了diff算法,通过对比新旧的两个虚拟dom树来检测那些dom是真的需要重新如安然,哪些dom是没有变化的。

diff算法

传统的diff算法是通过循环递归的方式对节点一次进行对比,需要O(n ^3)的时间复杂度。为什么?我们从最简单的说,把一棵树转换为另外一棵树,其实就是把一颗n个节点的树挨个儿去另一棵n个节点的树中查找,整个过程是n*n,那么如果发现有不同的地方,我们就需要需改,对一棵树的增删改的算法复杂度是n,那么整个过程就是n*n*n

react将这种对比策略做了一个优化,将复杂度降到了O(n),那么react是怎么实现的呢?react的diff会预设三个限制

  • 只进行同层级比较
  • 新旧节点的type不同,直接删除旧节点,创建新节点,比如组件不同,元素的类型不同,原来是ul,里面是li,后来改成了div+p,这个时候就会删除旧dom,创建新的dom.
  • 通过key来复用节点

在上面三个限制的基础上,对tree,conponent,element的处理方式又做了优化

  • dom节点不一致直接删除旧节点,创建新节点
  • 组件类型不一致直接删除组件下所有节点,创建新节点
  • 同一层的dom元素,以每个元素对应的key为标识,提供三种操作方式,删除新建和移动

diff的最小颗粒度

diff的最小颗粒度是标签,我们举例看一下

js 复制代码
class Hello extends React.Component {
   state={
       time:new Date()
   }
   componentDidMount(){
       this.timer=setInterval(()=>{
           this.setState({
               time:new Date()
           })
       },5000)
   }
   render() {
       console.log("i am render")
       return (
           <ul>
               <li>备注:<input type="text"/></li>
               <li><span>{this.state.time.toTimeString()}</span></li>
           </ul>
       )
   }
}

我们看到,每隔5秒,span标签就会从新刷新一次,而其他元素没有变化

key

前面我们说了,同一层级的元素如果发生了变化,可以删除 插入和移动,前提是必须有key作为标识,如果没有key,比如下面代码

js 复制代码
class Hello extends React.Component {
    state = {
        heros: [
            {
                id: 1,
                name: "张三"
            },
            {
                id: 2,
                name: "李四"
            }
        ]
    }
    render() {
        console.log("i am render")
        return (
            <ul>
                {this.state.heros.map((hero,index)=>{
                    return <li>{hero.name}</li>
                })}
            </ul>
        )
    }
}

这个时候浏览器提示了一个warm ,意思是每一个child都应该有唯一key。

那么这个key应该怎么选取呢

  • 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
  • 如果确定只是简单的展示数据,用index也是可以的。 但是不推荐。
    为什么不推荐index作为key,官方文档说,如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。

我们来举个例子对比一下,再分析问题所在。这段代码里,我点击添加按钮的时候,改变了原来数组对象的顺序,在数组的前头添加了一个对象,我们点击看一下效果

js 复制代码
class Hello extends React.Component {
    state = {
        heros: [
            {
                id: 1,
                name: "张三"
            },
            {
                id: 2,
                name: "李四"
            }
        ]
    }
    addHero=()=>{
        this.setState({
            heros: [
                {
                    id: 3,
                    name: "王五"
                },
                ...this.state.heros
            ]
        })
    }
    render() {
        console.log("i am render")
        return (
            <ul>
                <button onClick={this.addHero}>点击添加王五</button>
                <h1>index as key</h1>
                {this.state.heros.map((hero,index)=>{
                    return <li key={index}>{hero.name}<input type="text" /></li>
                })}
                <h1>age as key</h1>
                {this.state.heros.map((hero,index)=>{
                    return <li key={hero.id}>{hero.name}<input type="text" /></li>
                })}
            </ul>
        )
    }
}

我们发现了什么,以index做为key,input框并没有跟着往下移动,id作为key的往下移动了,我们发现问题了,那么为什么index作为key,input框不往下移动呢?就是因为数据的顺序发生变化了,王五被塞进了数组对象的头部,但是diff的时候,由于元素的key是index,还是从0开始的,并没有发生变化,所以input框并不会移动。

相关推荐
枫叶20001 小时前
OceanBase数据库-学习笔记4-租户
数据库·笔记·学习·oceanbase
灏瀚星空3 小时前
量化交易之数学与统计学基础2.4——线性代数与矩阵运算 | 矩阵分解
笔记·python·线性代数·信息可视化·矩阵
不吃香菜?4 小时前
逻辑回归在信用卡欺诈检测中的实战应用
算法·机器学习·逻辑回归
半导体守望者4 小时前
斯坦福RGA软件 老版本和兼容Windows 11版本可选
经验分享·笔记·功能测试·自动化·制造
Kay_Liang4 小时前
探究排序算法的奥秘(下):快速排序、归并排序、堆排序
java·数据结构·c++·python·算法·排序算法
禺垣4 小时前
AdaBoost算法的原理及Python实现
人工智能·python·算法·机器学习·数据挖掘·adaboost·集成学习
qq_508576094 小时前
混淆矩阵(Confusion Matrix)横坐标
人工智能·算法·机器学习
LSQ的测试日记5 小时前
机器学习_KNN算法
人工智能·算法·机器学习
炬火初现5 小时前
[leetcode]2302.统计得分小于k的子数组
算法·leetcode·职场和发展
江安的猪猪5 小时前
大连理工大学选修课——机器学习笔记(8):Boosting及提升树
笔记·机器学习·boosting