网站维护学习/产品推广计划方案

网站维护学习,产品推广计划方案,wordpress转换成dede,国内有哪些做卡通素材的网站概述 react 在渲染过程中要做很多事情,所以不可能直接通过初始元素直接渲染还需要一个东西,就是虚拟节点,暂不涉及React Fiber的概念,将vDom树和Fiber 树统称为虚拟节点有了初始元素后,React 就会根据初始元素和其他可…

概述

  • react 在渲染过程中要做很多事情,所以不可能直接通过初始元素直接渲染
  • 还需要一个东西,就是虚拟节点,暂不涉及React Fiber的概念,将vDom树和Fiber 树统称为虚拟节点
  • 有了初始元素后,React 就会根据初始元素和其他可以生成虚拟节点的东西生成虚拟节点
  • React一定是通过虚拟节点来进行渲染的

常用节点类型

  • 除了初始元素能生成虚拟节点以外,还有哪些可能生成虚拟节点?总共有多少节点类型?

1. Dom节点 (ReactDomComponent)

  • 此dom非彼dom, 这里的dom指的是虚拟dom节点,当初始化元素的type属性为字符串的时候
  • React 就会创建虚拟dom节点,例如,前面使用 jsx 直接书写的 const B = <div></div>
  • 它的属性就是div, 可以打印出来 { type: 'div' }

2. 组件节点 (ReactComposite)

  • class组件和函数式组件
  • type 有两类:class App 或 f Test() 这种举例

3. 文本节点 (ReactTextNode)

  • 直接书写字符串或数字,React 会创建为文本节点
  • 比如,我们可以直接用 ReactDOM.render 方法直接渲染字符串或数字
    import ReactDOM from 'react-dom/client';const root = ReactDOM.createRoot(document.getElementById('root'));// root.render('一头猪') // 创建文本节点
    root.render(1111); // 创建文本节点
    

4. 空节点(ReactEmpty)

  • 我们平时写 React 代码的时候,经常会写三目表达式 {this.state.xxx ? <App/> : false}
  • 用来进行条件渲染,只知道为 false 就不会渲染,到底是怎么一回事?
  • 其实,遇到字面量 null, false, true, undefined 在 React 中均会被创建一个空节点
  • 在渲染过程中,如果遇到空节点,那么它将什么都不会做
    import ReactDOM from 'react-dom/client'const root = ReactDOM.createRoot(document.getElementById('root'));
    // root.render(flase); // 创建空节点 // root.render(true);
    // 创建空节点 root.render(null)
    root.render(undefined) // 创建空节点
    

5. 数组节点(ReactArrayNode)

  • 不是渲染数组本身,当React遇到数组时,会创建数组节点,但是不会直接进行渲染
  • 而是将数组里的每一项按出来,根据不同节点类型去做相应的事情
  • 所以,数组里的每一项只能是这里提到的五个节点类型

渲染过程

  • 通过 document.createElement 创建的元素就是真实的dom
  • React 的工作是通过初始元素或可以生成虚拟节点的东西生成虚拟节点然后针对不同的节点类型去做不同的事情最终生成真实dom挂载到页面上
  • 渲染原理
    • 初始元素和可以生成虚拟节点的东西
    • 虚拟节点:根据不同的节点去做不同的事情
    • 挂载到界面(UI)

首次渲染阶段

  • React 会根据初始元素先生成虚拟节点,然后做了一系列操作后最终渲染成真实的UI

  • 根据不同的虚拟节点来看它到底做了些什么处理?

  • 1 )初始元素-dom节点

    • 对于初始元素的 type 属性为字符串时,React会通过 document.createElement 来创建真实DOM
    • 因为,初始元素的 type 为字符串,所以直接会根据 type 属性创建不同的真实DOM
    • 创建完真实DOM后立即设置该真实dom的所有属性,比如,直接在jsx中可以直接书写的 className, style 等都会作用到真实dom上
      // jsx 语法: React初始元素
      const B = <div class='wrapper' style={{color: 'red'}}><p className='text'>123</p>
      </div>
      
    • 当然 html 结构肯定不止一层,所以,在设置完属性后React会根据children属性进行递归遍历
    • 根据不同的 节点类型 去做不同的事情,同样的,如果 children 是初始元素,创建真实dom、设置属性
    • 然后检查是否有子元素,重复次步骤,移植到最后一个元素位置,遇到其他节点类型会做以下事情
  • 2 )初始元素-组件节点

    • 如果初始元素的 type 属性是一个 class 类 或 function 函数时
    • 那么会创建一个组件节点,所以,针对类或函数组件, 它的处理是不同的
    • 函数组件
      • 对于函数组件会直接调用函数,将函数的返回值进行递归处理
      • 看看是什么节点类型,然后去做对应的事情,所以一定要返回能生成虚拟节点的东西
      • 最终生成一棵vDOM树
    • 类组件
      • 对于类组件而言,会相对麻烦一些
        • a. 首先创建类的实例(调用constructor)
        • b. 调用生命周期方法 static getDerivedStateFromProps
        • c. 调用生命周期方法 render, 根据返回值递归处理,跟函数组件处理返回值一样,最终生成一棵 vDom树
        • d. 将该组件的生命周期方法 componentDidMount 加入到执行队列中等待真实dom挂载到页面后执行
        • 注意
          • 前面说了 render 是一个递归处理,所以如果一个组件存在 父子关系的时候
          • 那么肯定要等子组件渲染完
        • 父组件才能走出 render, 所以,子组件的 componentDidMount 一定是比父组件
        • 先入队列的,肯定先运行
  • 3 )文本节点

    • 针对文本节点,会直接通过 document.createTextNode 创建真实的文本节点
  • 4 )空节点

    • 如果生成的是 空节点,那么它将什么都不会做
  • 5 )数组节点

    • 就像前面提到的一样,React不会直接渲染数组,而是将里面的每一项拿出来遍历
    • 根据不同的节点类型去做不同的事,直到递归处理完数组里的每一项 (这里流一个问题,为何数组里要写 key)
  • 注意,嵌套组件渲染时的大致执行顺序

    • 先执行父组件的 constructor, getDerivedStateFromProps, render
    • 再执行子组件的 constructor, getDerivedStateFromProps, render, componentDidMount
    • 最后执行父组件的 componentDidMount

更新与卸载

  • 挂载完成后组件进入活跃状态,等待数据的更新进行重新渲染
  • 那么到底有几种场景会触发更新?整个过程又是怎么样的,有哪些需要注意的地方?

组件更新(setState)

  • 最常见的,我们经常用 setState 来重新设置组件的状态进行重新渲染
  • 使用setState只会更新调用此方法的类。不会涉及到兄弟节点以及父级节点
  • 影响范围仅仅是自己的子节点,步骤如下:
    • 1 ) 运行当前类组件的生命周期静态方法static getDerivedStateFromProps,根据返回值合并当前组件的状态
    • 2 ) 运行当前类组件的生命周期方法shouldComponentUpdate,如果该方法返回的false,直接终止更新流程
    • 3 ) 运行当前类组件的生命周期方法render,得到一个新的vDom树,进入新旧两棵树的对比更新
    • 4 ) 将当前类组件的生命周期方法 getSnapshotBeforeUpdate 加入执行队列,等待将来执行
    • 5 ) 将当前类组件的生命周期方法 componentDidUpdate 加入执行队列,等待将来执行
    • 6 ) 重新生成vDom树
    • 7 ) 执行队列,此队列存放的是更新过程涉及到原本存在的类组件的 生命周期 方法 getSnapshotBeforeUpdate
    • 8 ) 根据vDom树更新真实DOM
    • 9 ) 执行队列,此队列存放的是更新过程涉及到原本存在的类组件的 生命周期 方法 componentDidUpdate
    • 10 ) 执行队列,此队列存放的是更新过程中所有卸载的类组件的 生命周期方法 compoentWillUnmount

根节点更新(ReactDOM.createRoot().render)

  • 在ReactDOM的新版本中,已经不是直接使用 ReactDOM.render 进行更新了
  • 而是通过 createRoot (要控制的DOM区域)的返回值来调用 render
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import'./index.css';
    import App from'./App';const root = ReactDOM.createRoot(document.getElementById('root');
    root.render(<App/>
    );
    

对比更新过程(diff)

  • 知道了两个更新的场景以及会运行哪些生命周期方法后,我们来看一下具体的过程到底是怎么样的。
  • 所谓对比更新就是将新vDom树跟之前首次渲染过程中保存的老vDom树对比发现差异然后去做一系列操作的过程。
  • 那么问题来了,如果我们在一个类组件中重新渲染了,React怎么知道在产生的新树中它的层级呢?
  • 难道是给vDom树全部挂上一个不同的标识来遍历寻找更新的哪个组件吗?
  • 当然不是,我们都知道React的diff算法将之前的复杂度0(n^3)降为了0(n)
  • 它做了以下几个假设:
    • 1.假设此次更新的节点层级不会发生移动(直接找到旧树中的位置进行对比)
    • 2.兄弟节点之间通过key进行唯一标识
    • 3.如果新旧的节点类型不相同,那么它认为就是一个新的结构
      • 比如之前是初始元素div现在变成了初始元素 span那么它会认为整个结构全部变了,
      • 无论嵌套了多深也会全部丢弃重新创建

key的作用

  • 如果列表里面有初始元素,并且没有给初始元素添加 key那么它会警告

    • Warning: Each child in a list should have a unique “key” prop. 。
  • 那么 key值到底是干嘛用的呢?

    • 其实key的作用非常简单,仅仅是为了通过旧节点
    • 寻找对应的新节点进行对比提高节点的复用率
  • 现在来举个例子,假如现在有五个兄弟节点更新后变成了四个节点

  • 未添加key

  • 添加了key

找到对比目标-节点类型一致

  • 经过假设和一系列的操作找到了需要对比的目标
  • 如果发现节点类型一致,那么它会根据不同的节点类型做不同的事情
  1. 初始元素-DOM节点
  • 如果是DOM节点,React会直接重用之前的真实DOM
  • 将这次变化的属性记录下来,等待将来完成更新
  • 然后遍历其子节点进行递归对比更新
  1. 初始元素-组件节点
  • 函数组件
    • 如果是函数组件,React仅仅是重新调用函数拿到新的vDom树,然后递归进行对比更新
  • 类组件
    • 针对类组件,React也会重用之前的实例对象。后续步骤如下:
    • 1.运行生命周期静态方法static getDerivedStateFromProps。将返回值合并当前状态
    • 2.运行生命周期方法shouldComponentUpdate,如果该方法返回false,终止当前流程
    • 3.运行生命周期方法render,得到新的vDom树,进行新旧两棵树的递归对比更新
    • 4.将生命周期方法getSnapshotBeforeUpdate加入到队列等待执行
    • 5.将生命周期方法componentDidUpdate加入到队列等待执行

3.文本节点

  • 对于文本节点,同样的React也会重用之前的真实文本节点。
  • 将新的文本记录下来,等待将来统一更新(设置nodeValue)

4.空节点

  • 如果节点的类型都是空节点,那么React啥都不会做

5.数组节点

  • 首次挂载提到的,数组节点不会直接渲染
  • 在更新阶段也一样,遍历每一项,进行对比更新,然后去做不同的事

找到对比目标-节点类型不一致

  • 如果找到了对比目标,但是发现节点类型不一致了,这时候类型变了,那么你的子节点肯定也都不一样了
  • 就算一万个子节点,并且他们都是没有变化的,只有最外层的父节点的节点类型变了
  • 照样会全部进行卸载重新创建,与其去一个个递归查看子节点,不如直接全部卸载重新创建
    import'./App.css';
    import React from 'react';function Count(props) {console.log('Count')return <h1>{props. count}</h1>
    }class App extends React. Component {constructor() {super()this.state={arr:[1,2,3]}this.update =this.update.bind(this)}update() {this.setState({arr: [1,2,3,4]})}render() {console.log('父亲render执行')return (<div><button onClick={this.update}>点我更新</button>{ this.state.arr.map((count) => <Count key={count} count={count} />) }</div>)}
    }
    export default App;
    
    • 这个例子,初始化的时候,Count组件被初始化3次
    • 而点击更新的时候,Count组件更新了4次
    • 这是因为它是函数式组件,更新时,仅仅是重新调用函数,拿到新的vDOM树
    • 在react内部加了key,可以复用的是底层的vDom的树,而非这个函数式组件
    • 函数式组件,每次渲染,都会重新执行这个函数,这里要分清两者的区别

未找到对比目标

  • 如果未找到对比的目标,跟 节点类型 不一致的做法类似,
  • 那么对于多出的节点进行挂载流程,对于旧节点进行卸载直接弃用
  • 如果其包含子节点进行递归卸载,对于初始类组件节点会多一个步骤,那就是运行生命周期方法componentWillUnmount。
  • 注意:
    • 尽量保持结构的稳定性,如果未添加key的情况下
    • 兄弟节点更新位置前后错位一个那么后续全部的比较都会错位导致找不到对比目标从而进行卸载新建流程,对性能大打折扣

总结

  • 对于首次挂载阶段
    • 需要了解React的渲染流程
    • 通过书写的初始元素和一些其他可以生成虚拟节点的东西来生成虚拟节点
    • 然后针对不同的节点类型去做不同的事情,最终将真实DOM挂载到页面上
    • 然后执行渲染期间加入到队列的一些生命周期,然后组件进入到活跃状态
  • 对于更新卸载阶段
    • 需要注意的是有几个更新的场景,以及key的作用到底是什么,有或没有会产生多大的影响
    • 还有一些小细节,比如条件渲染时,不要去破坏结构,尽量使用空节点来保持前后结构顺序的统一
    • 重点是新旧两棵树的对比更新流程
    • 找到目标,节点类型一致时针对不同的节点类型会做哪些事,类型不一致时会去卸载整个旧节点
    • 无论有多少子节点,都会全部递归进行卸载

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

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

相关文章

WSL外部SSH连接有效方法

前言 wsl作为windows下使用linux平台有效的手段之一&#xff0c;本文可以让win作为工作站&#xff0c;外部系统用来连接win下的wsl系统。 自动启动服务脚本 https://zhuanlan.zhihu.com/p/47733615 开机自启端口转发 wslname "Ubuntu-20.04" 要转发端口的Linux…

图(高阶数据结构)

目录 一、图的基本概念 二、图的存储结构 2.1 邻接矩阵 2.2 邻接表 三、图的遍历 3.1 广度优先遍历 3.2 深度优先遍历 四、最小生成树 4.1 Kruskal算法 4.2 Prim算法 五、最短路径 5.1 单源最短路径-Dijkstra算法 5.2 单源最短路径-Bellman-Ford算法 5.3 多源最…

MySQL简单配置GTID

前期规划 IP地址 角色 系统版本 内核 软件包名称 192.168.2.3 Mysql主服务器 CentOS Stream 9 5.14.0- 381.el9.x86_64 mysql-8.2.0-linux-glibc2.17-x86_64.tar.xz 192.168.2.4 Mysql从服务器 CentOS Stream 9 5.14.0- 381.el9.x86_64 mysql-8.2.0-linux-glibc…

Day 43 | 动态规划 1049. 最后一块石头的重量 II 、494. 目标和 、 474.一和零

1049. 最后一块石头的重量 II 题目 文章讲解 视频讲解 思路&#xff1a;dp[j] 表示容量为 j 的背包&#xff0c;最多可以背最大重量为dp[j]。 class Solution {public int lastStoneWeightII(int[] stones) {int sum 0;for (int i 0; i < stones.length; i) {sum stone…

Netty Review - ServerBootstrap源码解析

文章目录 概述源码分析小结 概述 ServerBootstrap bootstrap new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChannelInitializer<SocketChannel>() …

微信小程序(四十二)wechat-http拦截器

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.wechat-http请求的封装 2.wechat-http请求的拦截器的用法演示 源码&#xff1a; utils/http.js import http from "wechat-http"//设置全局默认请求地址 http.baseURL "https://live-api.ith…

HCIA-HarmonyOS设备开发认证V2.0-3.2.轻量系统内核基础-中断管理

目录 一、中断基础概念二、中断管理使用说明三、中断管理模块接口四、代码分析&#xff08;待续...&#xff09; 一、中断基础概念 在程序运行过程中&#xff0c;出现需要由 CPU 立即处理的事务时&#xff0c;CPU 暂时中止当前程序的执行转而处理这个事务&#xff0c;这个过程…

指纹浏览器如何颠覆传统浏览器的使用?

传统浏览器在互联网时代发挥了巨大的作用&#xff0c;但随着科技的不断进步和用户需求的不断变化&#xff0c;新一代的浏览器工具开始崭露头角。指纹浏览器作为一种创新性的浏览器工具&#xff0c;正逐渐颠覆传统浏览器的使用方式。本文将探讨指纹浏览器如何颠覆传统浏览器&…

【蓝桥杯单片机记录】IO基础与LED控制

目录 一、IO基础 1.1 IAP15F2K61S2芯片原理图 1.2不同工作模式 二、新建工程的一些补充 2.1 keil中没有IAP15F2K61S2的头文件 解决&#xff1a;在isp软件中找到如下​编辑 2.2keil中的芯片选择 2.3推荐字体 三、sbit关键字 四、LED控制 4.1原理图 4.2不能直接通过IO…

unity2017 遇到visual studio 2017(社区版) 30日试用期到了

安装unity2017 遇到visual studio 2017 30日试用期到了&#xff0c;网上百度搜了好多方法都没有成功。 最后用了这个方法&#xff1a; 1)启动vs2017&#xff0c;在弹出要登录的窗口之前&#xff0c;迅速的点击工具-》选项-》账户&#xff0c;勾选在添加账户或对账户重新进行身…

origin技巧

origin技巧 1.去掉白边2.曲线平滑3.合并多层图例3.图例换方向 1.去掉白边 ctrlu 2.曲线平滑 3.合并多层图例 3.图例换方向 图例右键 “图例” 水平排布修改图例字&#xff1a;双击图例修改 https://blog.csdn.net/m0_47746156/article/details/121295151 https://blog.csdn.…

MacOS - 菜单栏上显示『音量』

教程步骤 点击打开系统偏好『设置』&#xff0c;并找到『控制中心』 在『控制中心模块』找到『声音』&#xff0c;选择『始终在菜单栏显示』

1g的视频怎么压缩到200m?3个步骤解决~

把1G的文件压缩到200M&#xff0c;可以有效节省存储空间&#xff0c;加快传输速度&#xff0c;在某些情况下&#xff0c;压缩文件可以提供更好的安全性&#xff0c;例如通过加密或压缩算法保护文件内容。下面就向大家介绍3个好用的方法。 方法一&#xff1a;使用嗨格式压缩大师…

游泳可以戴的耳机有哪些,游泳耳机哪个牌子好性价比高

在游泳训练中&#xff0c;尤其是在进行长距离游泳、控制节奏和进行长时间游泳燃脂时&#xff0c;很容易感到单调乏味。为了帮助自己完成每一个来回&#xff0c;许多游泳运动员除了依赖能量棒和功能饮料外&#xff0c;还会选择通过音乐提高注意力和兴奋度。研究表明&#xff0c;…

2.11日学习打卡----初学RocketMQ(二)

2.11日学习打卡 一. RocketMQ整合springboot 首先配置pom.xml文件 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency><dependency>…

记录一下,我使用stm32实现pwm波输入,以及对频率和占空比的计算,同时通过串口输出(实现-重要)

1&#xff0c;首先看下半物理仿真 看下我的配置&#xff1a; 看下计算方法以及matlab的仿真输出的数据&#xff1a; timer3的ch2是选择高电平&#xff0c;计算频率 timer3的ch1是选择的是低电平&#xff0c;用来计算周期 其中TemPIpre表示的是CH2输出的值&#xff0c; TemPI…

用HTML5 + JavaScript绘制花、树

用HTML5 JavaScript绘制花、树 <canvas>是一个可以使用脚本 (通常为JavaScript) 来绘制图形的 HTML 元素。 <canvas> 标签/元素只是图形容器&#xff0c;必须使用脚本来绘制图形。 HTML5 canvas 图形标签基础https://blog.csdn.net/cnds123/article/details/112…

Linux--常用命令(详解)

详细目录 一、终端命令格式二、显示文件列表命令-ls2.1作用2.2格式2.3 ls常用选项2.3.1 ls -a2.3.2 ls -l(等价于 ll)2.3.2 ls -h 三、相对路径与绝对路径3.1绝对路径3.2相对路径 四、目录操作命令 -cd4.1作用4.2格式4.3案例4.3.1 cd -&#xff1a; 返回上一次所在目录4.3.2 cd…

使用maven命令安装Oracle的jar包到本地仓库

mvn install:install-file -DgroupIdcom.oracle -DartifactIdojdbc6 -Dversion11.2.0.4 -Dpackagingjar -DfileD:\ojdbc6-11.2.0.4.jar ojdbc6-11.2.0.4.jar 下载 链接&#xff1a;https://pan.baidu.com/s/1SqO3Ug7KF8kGr9-jOy3MJQ 提取码&#xff1a;36p9

「Linux」用户操作

root用户 su&#xff1a;切换账户 语法&#xff1a;su [–] [用户名] -&#xff1a;可选&#xff0c;表示是否在切换用户后加载环境变量&#xff0c;建议带上用户名&#xff1a;表示要切换的用户&#xff0c;省略时表示切换到root切换用户后&#xff0c;通过exit命令退回上一个…