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

news2025/1/19 20:42:48

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的最小颗粒度是标签,我们举例看一下

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,比如下面代码

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 值,因为这样做会导致性能变差,还可能引起组件状态的问题。

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

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框并不会移动。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469907.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计推特(Leetcode355)

例题&#xff1a; https://leetcode.cn/problems/design-twitter/ 分析&#xff1a; 推特其实类似于微博&#xff0c;在微博中可以发送文章。 求解这类题目&#xff0c;我们需要根据题目需求&#xff0c;利用面向对象的思想&#xff0c;先对需求做一个抽象&#xff0c;看看能…

自定义 Git Hook

前言 前端同学大概都熟悉 husky 这个工具&#xff0c;他可以直接在项目中添加 git hooks&#xff0c;主要解决了 git hooks 不会同步到 git 仓库的问题&#xff0c;保证了每个开发人员的本地仓库都能执行相同的 git hooks。 但是 husky 毕竟是一个 JS 生态的工具&#xff0c;…

ChatGPT助您提升求职技能

目录 ChatGPT可以作为求职技能的学习和提升平台 ChatGPT可以帮助求职者提升沟通和表达能力 ChatGPT还可以帮助求职者提升问题解决能力和创新能力 ChatGPT还可以帮助求职者建立自信心和自我推销能力 随着科技的迅速发展&#xff0c;人们的生活方式和工作方式也在不断地变革。…

移动端自动化常用的元素定位工具 介绍

在移动端自动化测试和开发中&#xff0c;元素定位是非常关键的一步。以下是一些常用的工具和技术来帮助开发者或测试工程师在移动设备上定位元素&#xff1a; 1. **UiAutomator**: - **UiAutomator** 是 Android 官方提供的自动化测试框架。它可以用来编写测试脚本&…

交易快讯:4拼域名以10,000元被秒

交易新闻 ——30万美元易手&#xff0c;60万美元易手&#xff0c;.au 10万美元易主。 近期&#xff0c;域名交易金额可能达到130万美元&#xff08;逾130万元人民币&#xff09;。 ——双拼在域名交易平台上以2万元的固定价格进行交易。 该域名直接对应了南瓜的含义。 另外&a…

CSRF靶场实战

DVWA靶场链接&#xff1a;https://pan.baidu.com/s/1eUlPyB-gjiZwI0wsNW_Vkw?pwd0b52 提取码&#xff1a;0b52 DVWA Low 级别打开靶场&#xff0c;修改密码 复制上面的 url&#xff0c;写个简单的 html 文件 <html <body> <a hrefhttp://127.0.0.1/DVWA/vulne…

常见的排序算法整理

1.冒泡排序 1.1 冒泡排序普通版 每次冒泡过程都是从数列的第一个元素开始&#xff0c;然后依次和剩余的元素进行比较&#xff0c;若小于相邻元素&#xff0c;则交换两者位置&#xff0c;同时将较大元素作为下一个比较的基准元素&#xff0c;继续将该元素与其相邻的元素进行比…

企业型多域名SSL证书

多域名SSL证书是目前市场上用的比较多的一种&#xff0c;主要解决多个不同规则的域名申请&#xff0c;但不适合主域名&#xff08;根域名&#xff09;相同的域名&#xff0c;因为这种域名直接申请通配符。 企业型其实就是OV类型或者EV类型&#xff0c;由于在CA/B产品名称规范中…

day13_String字符串的使用-课后练习 - 参考答案

文章目录 day13_课后练习代码编程题第1题第2题第3题第4题第5题第6题第7题第8题第9题第10题第11题第12题第13题 代码阅读题第14题第15题第16题第17题第18题第19题第20题 day13_课后练习 代码编程题 第1题 反转键盘录入的字符串。代码实现&#xff0c;参考效果如图所示&#x…

孙艺洲驾考再传捷报,科目二通过。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 在《飞驰人生2》的首映礼盛大举行的日子里&#xff0c;猴哥意…

基于ZYNQ的PCIE高速数据采集卡的设计(五)上位机软件设计

4.4 上位机软件设计 上位机主要完成数据的接收和保存文件等功能。由于采集卡是一种 PCIE 设备&#xff0c; 需要一种 PCIE 设备的驱动程序为基础进行开发。本设计选择 WinDriver 开发工具来 生成 PCIE 设备驱动和函数库&#xff0c;并基于该驱动在 Visual Studio(…

标准化特征数据:优化梯度下降计算

目录 前言1 特征数据的缩放2 均值归一化3 Z-Score 归一化结语 前言 在机器学习和深度学习中&#xff0c;特征的大小和参数的大小对模型的训练效果起着至关重要的作用。特别是在涉及多个特征的情况下&#xff0c;不同特征之间可能存在较大的差异&#xff0c;这会对梯度下降的计…

算法沉淀——动态规划之简单多状态 dp 问题(上)(leetcode真题剖析)

算法沉淀——动态规划之简单多状态 dp 问题上 01.按摩师02.打家劫舍 II03.删除并获得点数04.粉刷房子 01.按摩师 题目链接&#xff1a;https://leetcode.cn/problems/the-masseuse-lcci/ 一个有名的按摩师会收到源源不断的预约请求&#xff0c;每个预约都可以选择接或不接。在…

软件工程复习笔记

一、软件工程概述 软件 = 程序 + 数据 + 相关文档 软件危机(Software Crisis) 指由于落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现一系列严重问题的现象。 软件工程三要素 方法、工具、过程 软件工程目标 在给定成本、进度的…

【Linux】 yum命令使用

yum命令 yum&#xff08; Yellow dog Updater, Modified&#xff09; 是一个在 Fedora、CentOS 及其它一些基于 RPM 的 Linux 发行版中使用的包管理器。它允许用户自动安装、更新、配置和删除软件包。yum 由 Python 写成&#xff0c;基于 RPM&#xff08;Red Hat Package Mana…

Vue3路由组件练习

Vue3 路由组件练习 演示效果代码分析 安装 vue-router创建路由文件创建路由实例使用 router-link 组件导航 代码实现 index.js 文件App 文件 1. 演示效果 2. 代码分析 2.1. 安装 vue-router 命令&#xff1a;npm i vue-router 应用插件&#xff1a;Vue.use(VueRouter) 2.2…

linux僵尸进程

僵尸进程&#xff08;Zombie Process&#xff09;是指在一个进程终止时&#xff0c;其父进程尚未调用wait()或waitpid()函数来获取该进程的终止状态信息&#xff0c;导致进程的资源&#xff08;如进程表中的记录&#xff09;仍然保留在系统中的一种状态。 当一个进程结束时&am…

C语言数据存储

目录 一.数据类型的介绍 &#xff08;1&#xff09;整形家族 &#xff08;2&#xff09;浮点型家族 &#xff08;3&#xff09;构造类型 &#xff08;4&#xff09;其他 二.整形在内存中如何进行存储 &#xff08;1&#xff09;原&#xff0c;反&#xff0c;补 &#xf…

Spring解决循环依赖

目录 什么是spring循环依赖 什么情况下循环依赖可以被处理&#xff1f; spring 如何解决循环依赖 创建A这个Bean的流程 答疑 疑问&#xff1a;在给B注入的时候为什么要注入一个代理对象&#xff1f; 初始化的时候是对A对象本身进行初始化&#xff0c;而容器中以及注入到B…

三维模型轻量化、格式转换、可视化、数字孪生综合服务平台

老子云概述 老子云3D可视化快速开发平台&#xff0c;集云压缩、云烘焙、云存储云展示于一体&#xff0c;使3D模型资源自动输出至移动端PC端、Web端&#xff0c;能在多设备、全平台进行展示和交互&#xff0c;是全球领先、自主可控的自动化3D云引擎。 平台架构 平台特性 基于 …