getDerivedStateFromProps和componentDidUpdate的使用

2023-10-27

react 17版本

  • 使用getDerivedStateFromProps接收外部数据同步到本地state。
  • componentDidUpdate里面发送异步请求。

Foo.js

import { useState } from 'react'
import GetDerivedStateFromProps164plus from './GetDerivedStateFromProps164plus'
// 父组件重新render引起子组件重新render的情况有两种
const App = () => {
  const [data, setData] = useState(111)
  return (
    <>
    <button onClick={() => setData(data)}>addData 父组件不更新data</button>
    <button onClick={() => setData(data + 1)}>addData + 1 父组件更新data</button>
    <GetDerivedStateFromProps164plus data={data}></GetDerivedStateFromProps164plus> 
    </>
  )
}
export default App

Child.js

import React, { Component, useState } from 'react'

// (React v16.3中)getDerivedStateFromProps 本来是只在创建和更新(由父组件引发部分)中调用。如果不是由父组件引发,
// 那么getDerivedStateFromProps也不会被调用,如自身setState引发或者forceUpdate引发。

// (React v16.4中)改正了这一点,让getDerivedStateFromProps无论是Mounting还是Updating,
// 也无论是因为什么引起的Updating,全部都会被调用
class Child extends Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [3,4,5],
      data: 1,
      props: '' // 绑定一个props引用,设置为空方便下次传入的时候比较,并且能在第一次传入的时候执行state.data同步。如果是直接将super的props赋值给state.props,则第一次不会同步,因为props的值相同。
    }
    console.log(this.state)
  }
  // static getDerivedStateFromProps(prevprops, nextState)
  // 函数作用:这个函数主要是用来代替 componentWillReceiveProps,作用是接收props转换成本地的state。
  // 参数:props是传入的props,state是更新后的state
  // 返回值:在组件创建时和更新时的render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容。
  // 返回值:null或者一个新的state对象。
  // 这里无法访问this。因为static变量只能被class访问,而无法被实例访问。
  // 即可以Child.xxx,而不能(new Child()).xxx
  static getDerivedStateFromProps(prevprops, nextState) {
    console.log('getDerivedStateFromProps (1)')
    console.log(prevprops.data !== nextState.props.data)
    console.log(prevprops.data)
    console.log(nextState.props.data)
    console.log(nextState.data)
    // 如果props传入值和原来的值不一样,则重新给state赋值
    if(prevprops.data !== nextState.props.data) {
      return {
        data: prevprops.data,
        props:{...prevprops}
      }
    }
    // 默认不改变state。
    return null
  }
  
  // 异步加载,参数如果更新则发送请求
  componentDidUpdate(prevProps, prevState) {
    console.log('componentDidUpdate (3)')
    console.log(prevProps)
    console.log(this.state.data)
    console.log(prevState.data)
    // 和之前的state.data对比,发现参数更新了,则执行请求。
    console.log(prevState.data !== this.state.data)
    if(prevState.data !== this.state.data) {
      return this._doAsyncOperation(this.state.data)
    };
  }

  // 感觉比在componentDidUpdate中更实时更新
  // componentWillReceiveProps(nextProps) {
  //   if (this.props.data !== nextProps.data) {
  //       // 在这里进行异步操作或者更新状态
  //       this.setState({
  //           data: this.props.data,
  //       });
  //       this._doAsyncOperation(this.props.data);
  //   }
  // }
  
  // 有数据更新则通过,否则不更新组件。
  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate(2)')
    console.log('外部数据: ',nextProps.data , this.state.data)
    console.log('list是否改变:', nextState.list !== this.state.list)
    console.log('data是否改变:', this.state.data !== nextState.data)
    console.log('本地总数据是否改变:', this.state.list !== nextState.list || this.state.data !== nextState.data )
    console.log('本地数据:', this.state, nextState)
    // 外部变量判断
    // 外部更新数据,需要渲染
    if(nextProps.data !== this.state.data) {
      return true
    }
    // 本地变量判断
    if( this.state.list !== nextState.list || this.state.data !== nextState.data ) {
      return true
    }
    return false
  }
  
  // 请求数据
  _doAsyncOperation = (params) => {
    setTimeout(() => {
      let data = this.state.list.slice()
      data.push(params)
      this.setState({
        list: [...data]
      })
    }, 1000)
  }
  handleClick = () => {
    this.setState({
      data: this.state.data
    })
  }
  handleClick2 = () => {
    this.setState({
      data: this.state.data + 1
    })
  }
  render () {
    return (
      <div>
        <hr></hr>
        --- propsToState Render ----
        <br />
        {console.log('propsToState Render')}
        <p>
          props: {this.props.data}
        </p>
        <p>
          state: {this.state.data}
        </p>
        <ul>
        {
          this.state.list.map((item, index) => (
            <li key={index}>{item}</li>
            ))
          }
        </ul>
        <button onClick={this.handleClick}>addData</button>
        <button onClick={this.handleClick2}>addData + 1</button>
      </div>
    )
  }
}
export default Child

效果:
  1. 父子组件的addData按钮不会触发更新
  2. addData+1按钮会触发更新,列表增加item
  3. 父组件addData+1按钮,这个看传入的值和本地的state是否相同,相同则不更新,否则更新。
请求的整个流程如下:
  1. 子组件点击addData+1按钮,更新state.data
  2. 走getDerivedStateFromProps判断,无更新
  3. 走组件更新shouldComponentUpdate,需要更新state.data
  4. 组件渲染完毕走componentDidUpdate,data发生改变,请求数据
  5. 异步请求后更新state。
  6. 从新进入循环判断,即回到2-4
  7. 走getDerivedStateFromProps判断,无更新
  8. 走组件更新shouldComponentUpdate,需要更新state.list
  9. 组件渲染完毕走componentDidUpdate,data无变更,不再请求数据。

如果是父组件点击addData+1按钮,则是多了走stateToProps的更新步骤,然后走到shouldComponentUpdate则看是否和本地数据一样,如果一样就被中断更新state.data,也就不会再去发送请求。

参考:React生命周期(包括react16版)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

getDerivedStateFromProps和componentDidUpdate的使用 的相关文章

  • 如何在react-bootstrap中禁用表单提交的

    在下面的代码片段中 我有许多文本类型的输入表单 如果用户点击 我似乎会得到相同的合成事件 就像他们按下提交按钮一样 我想忽略作为表单提交 只允许一个人按下 提交 按钮 我删除了一些表单组以减少示例 在所有情况下 按钮或 ENTER 键 e
  • 使用 JavaScript 禁用第三方 cookie

    我正在努力根据所有在欧盟运营的公司的数据保护规则实施新的 Cookie 政策合规性 根据该规则 用户在使用任何网站时必须能够拒绝 接受除必需的 Cookie 之外的所有内容 在我客户的网站中 我可以看到正在存储以下第三方 cookie ga
  • 如何将内联 JavaScript 与 Express/Node.js 中动态生成的内容分开?

    对于具有几年 Web 开发经验但没有找到答案的人来说 这是一个有点菜鸟的问题程序员堆栈交换 or Google 我决定在这里问一下 我在用Express网络框架Node js 但这个问题并不特定于任何 Web 框架或编程语言 以下是从数据库
  • 引导程序提前输入未填充承诺的响应

    我的引导程序预输入如下
  • 在打字稿中导入 json

    我是 typescript 的新手 在我的项目中 我们使用 typescript2 在我的要求之一中 我需要导入 json 文件 所以我创建了 d ts 文件如下 test d ts declare module json const va
  • 如何让 Django 和 ReactJS 协同工作?

    New to Django and even newer to ReactJS I have been looking into AngularJS and ReactJS but decided on ReactJS It seemed
  • 如何将函数附加到弹出窗口关闭事件(Twitter Bootstrap)

    我做了一些搜索 但我只能认为我可以将事件附加到导致其关闭的按钮 https stackoverflow com questions 13205103 attach event handler to button in twitter boo
  • 如何制作没有 ng-repeat 的模板并使用 Angular-drag-and-drop-lists 将数据传递到 $scope?

    我想用角度拖放列表 https github com marceljuenemann angular drag and drop lists使用我自己的网格模板到所见即所得编辑器 如何构建我自己的 HTML 模板而不需要ng repeat因
  • 在 HTML5 画布中,如何用我选择的背景遮盖图像?

    我试图用画布来实现这一点 globalCompositeOperation 但没有运气 所以我在这里问 这里有类似的问题 但我没有在其中找到我的案例 我的画布区域中有图层 从下到上的绘制顺序 画布底座填充纯白色 fff 用fillRect
  • 刷新页面时保存用户的选择

    我目前有一个页面显示不同团队的数据 我有一些数据 用户可以单击使其处于 打开 或 关闭 状态 并为每个数据显示不同的图标 它基本上就像一个清单 只是没有物理复选框 我想记住哪些 复选框 已被选中 即使在用户刷新页面或关闭浏览器并稍后返回之后
  • 将 UMD Javascript 模块导入浏览器

    你好 我正在对 RxJS 进行一些研究 我可以通过在浏览器中引用它来使用该库 如下所示 它使用全局对象命名空间变量 Rx 导入 我可以制作可观察的东西并做所有有趣的事情 当我将 src 更改为指向最新的 UMD 文件时 一切都会崩溃 如下所
  • 可以设置标题样式吗? (并且使用CSS或js?)[重复]

    这个问题在这里已经有答案了 我想知道是否可以设计一个title a href title This is a title Hello a 样式问题有两个方面 文本格式 编码 我猜这是可能的 所以在问题中这样做 工具提示样式 你能把它弄大一点
  • Three.js 各种大小的粒子

    我是 Three js 的新手 正在尝试找出添加 1000 个粒子的最佳方法 每个粒子都有不同的大小和颜色 每个粒子的纹理是通过绘制画布创建的 通过使用粒子系统 所有粒子都具有相同的颜色和大小 为每个粒子创建一个粒子系统是非常低效的 有没有
  • 在 Javascript 中连接空数组

    我正在浏览一些代码 我想知道这有什么用处 grid push concat row 根据我的理解 它等同于 grid push row 为什么要大惊小怪 连接 你想使用 concat当您需要展平数组并且没有由其他数组组成的数组时 例如 va
  • 使用 ApolloClient 从 useContext 挂钩导入一个简单变量

    我的反应相对较新 似乎无法导入client来自上下文的变量 我有一个名为 federation tsx 的文件 其中包含一些代码 我相信这应该是相关部分 const link createHttpLink uri process env U
  • 带参数的事件监听器

    我想将参数传递给 JavaScript 中的事件侦听器 我已经找到了解决方案 但我无法理解它们为什么或如何工作以及为什么其他解决方案不起作用 我有 C C 背景 但是 Javascript 函数的执行有很大不同 您能否帮助我理解以下示例如何
  • 使用 Vite 和 React 进行生产构建时出错:Uncaught TypeError 中的错误:_ 不是函数

    我在我的网站上使用 Vite React React Router 和 TypeScript 我在运行生产构建时遇到问题 在开发模式下一切正常 使用生产版本时 我的浏览器显示白色背景 并且在浏览器控制台中出现以下错误 上面的链接将我带到第
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • 在 CKEditor 中设置字体大小和字体系列

    我正在使用 ckeditor 我想问一下这个插件如何设置font family和font size 我尝试过使用 CKEDITOR config font defaultLabel Arial CKEDITOR config fontSiz
  • Jquery - 选择选项后如何获取选项的特定数据类型?

    我将直接跳到标记 然后解释我想要做什么 HTML 选择选项

随机推荐

  • Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

    为什么要写这篇文章 1 因为最近在学习 软件调试 这本书 看到书中的某个调试历程中讲了Windows的系统调用的实现机制 其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数 2 碰巧前天又在网上看到了
  • mapboxgl 添加带注记marker

  • 现有的评分和排名算法

    前言 在之前的文章 投票 公平 中已经得到了一个令人沮丧的结论 只有道德上的相对民主 没有制度上的绝对公平 投票是对不同选项或个体的排序 在投票中我们关注更多的是相对位置这样定性的结论 例如 积分前三名的同学才能进入下一环节 但有的时候我们
  • [python网站开发] 一.Django入门知识及创建第一个网站

    随着Python应用越来越广泛 学习Python相关知识越来越多的人选择 最新研究 Python已成为美国top高校最受欢迎的语言 同时国内用Python开发的网站越来越多 比较知名的网站如知乎 豆瓣 果壳等 再加上之前自己数据分析和网络爬
  • 本地部署 langchain-ChatGLM

    简介 什么是 langchain ChatGLM 一种利用 ChatGLM 6B langchain 实现的基于本地知识的 ChatGLM 应用 增加 clue ai ChatYuan 项目的模型 ClueAI ChatYuan large
  • 成为机器人工程师需要学习那些技术

    机器人工程师是未来比较吃香的工作岗位 要成为机器人工程师 ChatGPT的回答是 建议你需要学习以下技术 1 机械工程 了解机械结构 运动学和动力学 以及机械设计和制造方面的知识 2 电子工程 学习电路设计 电子元件选择和电子系统集成 以及
  • 初识Python装饰器

    Python装饰器 听过Python的人 肯定也听过装饰器的名头 但是好多人不明白装饰器是什么 是如何工作的 原理又是什么 先看看装饰器的定义 如果想要修改某个函数的功能 但是又不想修改这个函数的定义 这种在函数运行期间动态增加功能的方式成
  • ABP-使用Dapper框架

    ABP使用Dapper框架已经有很成熟的第三方包 简单的几句代码就能完成 一 首先准备好一个数据库建一个表 二 建一个实体表 Table BasBloodLevel public class BasBloodLevel Entity
  • 《设计模式》-代码质量评价标准和设计原则

    系列文章目录 设计模式 代码质量评价标准和设计原则 设计模式 创建型 单例模式 工厂模式 建造者模式 原型模式 设计模式 结构型 代理模式 装饰者模式 适配器模式 桥接模式 门面模式 组合模式 亨元模式 文章目录 系列文章目录 前言 一 代
  • 第10章 近似推断

    10 近似推断 在概率模型的应用中 一个中心任务是在给定观测 可见 数据变量X的条件下 计算潜在变量Z的后验概率分布 p Z X p Z X p Z X 以及计算
  • element表格翻页后回到顶部

  • Linux mode命令,linux命令

    一 inode节点号 在linux中 每一个文件都有唯一的inode号 inode号也是系统识别的唯一编码 而文件名仅仅是为了使用者区分辨认 inode index node 表中包含文件系统所有文件列表 一个节点 索引节点 是在一个表项
  • 数字IC设计——跨时钟域篇2(亚稳态)

    数字IC设计 跨时钟域篇2 亚稳态 一 建立时间与保持时间 前提条件 对任何一种触发器 在时钟触发沿前 后的一个小时间窗口内 输入信号必须稳定 输入信号应提前时钟上升沿 假设上升沿有效 T时间到达芯片 这个T就是建立时间Setup time
  • 海思3518E V200中RTSP实验自己构建RTP发送的函数代码及VLC播放器的一个播放注意事项

    在VLC播放器中 工具 首选项 设置里面需要注意必须使用下图中红色框圈出来的设置 如果选择的是后面的 RTP over RTSP TCP 的话会播放不出画面 具体原因未去深入探究 另可以参考他人的代码完成其他功能 网址如下 https bl
  • msi afterburner怎么设置最好?推荐设置

    msi afterburner是一款为显卡超频和监控提供的软件 广泛应用于游戏玩家和电脑爱好者之间 通过适当的设置 可以显著提升显卡的性能 下面就给大家介绍一下msi afterburner推荐设置 纯净之家 win7纯净版系统 win7
  • 使用Prometheus实现大规模的应用程序监视

    Prometheus是一个越来越受欢迎的开源工具 这有充分的理由 它可以为应用程序和服务器提供监视和警报 Prometheus的强大优势在于监视服务器端指标 并将其存储为时间序列数据 尽管Prometheus不适合应用程序性能管理 主动控制
  • 【转】一个FAE(AE)的体会和大家交流

    原文网址 http www 52rd com bbs dispbbs asp boardID 63 ID 228682 本人在国内某芯片设计公司工作近5年时间岗位是AE和FAE 两个工作量各一半吧 今日闲来无事写一些自己的体会与大家分享 不
  • 【一、搭建通用Arm平台的QT交叉编译环境】

    搭建通用Arm平台的QT交叉编译环境 前言 准备 一 下载arm平台交叉编译工具链 1 下载工具链 2 解压到交叉编译平台 Ubuntu 3 配置环境变量 二 下载QT源码 版本与交叉编译工具链版本保持一致 三 下载并编译tslib库 1
  • 微信小程序实现下载功能(以下载视频为例)

    首先 采用 wx downloadFile 方法 访问视频对应的Url 回调函数返回一个该视频文件的临时路径 wx downloadFile url app serverUrl me data videoInfo videoPath suc
  • getDerivedStateFromProps和componentDidUpdate的使用

    react 17版本 使用getDerivedStateFromProps接收外部数据同步到本地state componentDidUpdate里面发送异步请求 Foo js import useState from react impor