当前位置: 首页 > article >正文

【React】类组件更新的底层逻辑

目录

  • 创建一个构造函数(类)
  • 类组件初始化
    • 1. 初始化属性 && 规则校验
    • 2. 初始化状态
    • 3、触发 componentWillMount
    • 4、触发 render 进行渲染
    • 5、触发 componentDidMount
  • 组件更新的逻辑
    • 第一种:组件内部的状态被修改,组件会更新
      • 1、触发 shouldComponentUpdate
      • 2、触发 componentWillUpdate
      • 3、修改状态值/属性值
      • 4、触发 render
      • 5、 触发 componentDidUpdate
    • 第二种:父组件更新,触发的子组件更新
      • 1、触发 componentWillReceiveProps
      • 2、触发 shouldComponentUpdate 周期函数
  • 组件卸载的逻辑
    • 触发 componentWillUnmount
    • 销毁
  • 扩展:父子组件嵌套更新逻辑
    • 父组件第一次渲染
    • 父组件更新
    • 父组件销毁
  • 源码

创建一个构造函数(类)

  • 类组件必须继承自 React.ComponentReact.PureComponent
  • 在类组件中,需要定义 render 方法来返回需要渲染的视图。
  • 通常使用ES6中的class创建类。
class MyComponent extends React.Component {
  constructor(props) {
    super(props); // 调用父类构造函数
    console.log(this.props); // 获取传递的属性
    this.state = { count: 0 }; // 初始化状态
  }
  //返回渲染的视图
  render() {
    return <div>{this.state.count}</div>;
  }
}

类组件初始化

1. 初始化属性 && 规则校验

首先会进行规则校验,校验完毕后,再处理属性的其他操作。处理传进来的属性有两种处理方式:

方案一:

  constructor(props) {
        super(props); //会把传递进来的属性挂载到this实例上
        console.log(this.props); //获取到传递的属性
  }

方案二:

不在constructor中处理「或者constructor都没写」,在constructor处理完毕后,React内部也会把传递的props挂载到实例上。所以在其他的函数中,只要保证this是实例,就可以基于this.props获取传递的属性。同样this.props获取的属性对象也是被冻结的{只读的} Object.isFrozen(this.props)->true

2. 初始化状态

状态:后期修改状态,可以触发视图的更新。需要手动初始化,如果我们没有去做相关的处理,则默认会往实例上挂载一个state,初始值是null => this.state=null, 手动处理则需要写个state对象:

state = {
    ...
  };

如何修改状态,控制视图更新

  this.state.xxx=xxx

上面的操作仅仅是修改了状态值,但是无法让视图更新,想让视图更新,我们需要基于React.Component.prototype提供的方法操作:

  • this.setState(partialState) 既可以修改状态,也可以让视图更新 「推荐」 ,其中partialState部分状态
 this.setState({
       xxx:xxx
  });
  • this.forceUpdate() 强制更新

3、触发 componentWillMount

componentWillMount:组件第一次渲染之前触发。

钩子函数:在程序运行到某个阶段,我们可以基于提供一个处理函数,让开发者在这个阶段做一些自定义的事情

⚠️注意:此周期函数,目前是不安全的「虽然可以用,但是未来可能要被移除了,所以不建议使用」,控制会抛出黄色警告「为了不抛出警告,我们可以暂时用 UNSAFE_componentWillMount

⚠️注意:如果开启了React.StrictMode「React的严格模式」,则我们使用 UNSAFE_componentWillMount 这样的周期函数,控制台会直接抛出红色警告错误!!

React.StrictMode VS “use strict”

  • “use strict”:JS的严格模式
  • React.StrictMode:React的严格模式,它会去检查React中一些不规范的语法、或者是一些不建议使用的API等!!

4、触发 render 进行渲染

5、触发 componentDidMount

componentDidMount:第一次渲染完毕,此时已经把virtualDOM变为真实DOM了,可以获取真实DOM

组件更新的逻辑

第一种:组件内部的状态被修改,组件会更新

1、触发 shouldComponentUpdate

shouldComponentUpdate:是否允许更新,返回值决定视图是否需要更新

   shouldComponentUpdate(nextProps, nextState) {
     // nextState:存储要修改的最新状态
     // this.state:存储的还是修改前的状态「此时状态还没有改变」
     console.log(this.state, nextState);
     // 此周期函数需要返回true/false
     //   返回true:允许更新,会继续执行下一个操作
     //   返回false:不允许更新,接下来啥都不处理
     return true;
   }

2、触发 componentWillUpdate

componentWillUpdate:更新之前,此周期函数也是不安全的, 在这个阶段,状态/属性还没有被修改。

3、修改状态值/属性值

this.state.xxx改为最新的值

4、触发 render

进行组件渲染,处于经历下面过程:

  • 按照最新的状态/属性,把返回的JSX编译为virtualDOM
  • 和上一次渲染出来的virtualDOM进行对比「DOM-DIFF
  • 把差异的部分进行渲染「渲染为真实的DOM」

5、 触发 componentDidUpdate

componentDidUpdate:组件更新完毕。

⚠️注意:如果我们是基于 this.forceUpdate() 强制更新视图,会跳过 shouldComponentUpdate 周期函数的校验,直接从 componentWillUpdate 开始进行更新,也就是视图一定会触发更新。

第二种:父组件更新,触发的子组件更新

1、触发 componentWillReceiveProps

componentWillReceiveProps:接收最新属性之前,该周期函数是不安全的。

  UNSAFE_componentWillReceiveProps(nextProps) {
      // this.props:存储之前的属性
      // nextProps:传递进来的最新属性值
      console.log('componentWillReceiveProps:', this.props, nextProps);
  }

2、触发 shouldComponentUpdate 周期函数

接下来的逻辑跟第一种一样

组件卸载的逻辑

触发 componentWillUnmount

componentWillUnmount:组件销毁之前

销毁

扩展:父子组件嵌套更新逻辑

父子组件嵌套,处理机制上遵循深度优先原则:父组件在操作中,遇到子组件,一定是把子组件处理完,父组件才能继续处理

父组件第一次渲染

父 willMount -> 父 render「子 willMount -> 子 render -> 子didMount」 -> 父didMount

父组件更新

父 shouldUpdate -> 父willUpdate -> 父 render 「子willReceiveProps -> 子 shouldUpdate -> 子willUpdate -> 子 render -> 子 didUpdate」-> 父 didUpdate

父组件销毁

父 willUnmount -> 处理中「子willUnmount -> 子销毁」-> 父销毁

源码

import React from "react";
import PropTypes from 'prop-types';

class Vote extends React.Component {
  /* 属性规则校验 */
  static defaultProps = {
    num: 0
  };
  static propTypes = {
    title: PropTypes.string.isRequired,
    num: PropTypes.number
  };

  /* 初始化状态 */
  state = {
    supNum: 20,
    oppNum: 10
  };

  render() {
    console.log('render:渲染');
    let { title } = this.props,
      { supNum, oppNum } = this.state;

    return <div className="vote-box">
      <div className="header">
        <h2 className="title">{title}</h2>
        <span>{supNum + oppNum}</span>
      </div>
      <div className="main">
        <p>支持人数:{supNum}</p>
        <p>反对人数:{oppNum}</p>
      </div>
      <div className="footer">
        <button onClick={() => {
          this.setState({
            supNum: supNum + 1
          });
        }}>支持</button>

        <button onClick={() => {
          this.state.oppNum++;
          this.forceUpdate();
        }}>反对</button>
      </div>
    </div>;
  }

  UNSAFE_componentWillMount() {
    console.log('componentWillMount:第一次渲染之前');
  }

  componentDidMount() {
    console.log('componentDidMount:第一次渲染完毕');
  }


  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate:', this.state, nextState);
    return true;
  }

  UNSAFE_componentWillUpdate(nextProps, nextState) {
    console.log('componentWillUpdate:', this.state, nextState);
  }


  componentDidUpdate() {
    console.log('componentDidUpdate:组件更新完毕');
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    console.log('componentWillReceiveProps:', this.props, nextProps);
  }

  componentWillUnmount() {
    console.log('componentWillUnmount:组件销毁之前');
  }
}
export default Vote;

初始渲染:
在这里插入图片描述
点击支持:更新渲染:
在这里插入图片描述
点击反对,更新渲染,因为使用了forceUpdate(),所以直接跳过了shouldComponentUpdate周期:
在这里插入图片描述
父组件更新,触发的子组件更新,这次回触发componentWillReceiveProps
在这里插入图片描述
组件更新渲染逻辑如下图所示
在这里插入图片描述
简单总结一下:

组件初始化阶段

  • constructor(props):用于初始化组件的属性和状态。
  • UNSAFE_componentWillMount():在组件渲染前调用,但不推荐使用,可能在未来版本中被移除。
  • render():渲染组件,返回 JSX 元素。
  • componentDidMount():在组件渲染完成后调用,可以在此进行异步操作或 DOM 操作。

组件更新阶段

  • shouldComponentUpdate(nextProps, nextState):用于决定组件是否需要更新,返回 true 或 false。
  • UNSAFE_componentWillUpdate(nextProps, nextState):在组件更新前调用,但不推荐使用,未来可能移除。
  • `render():再次渲染组件。
  • componentDidUpdate(prevProps, prevState):组件更新后调用,可以在此进行后续操作。

组件卸载阶段

  • componentWillUnmount():在组件销毁之前调用,可以在此进行清理操作,如取消订阅、清除定时器等。

http://www.kler.cn/a/512350.html

相关文章:

  • Ubuntu22部署MySQL5.7详细教程
  • 麒麟系统中删除权限不够的文件方法
  • 【HarmonyOS-开发指南】
  • 内存故障原因与诊断(Reasons and Diagnosis of Memory Failure)
  • git操作
  • 【Django开发】django美多商城项目完整开发4.0第12篇:商品部分,表结构【附代码文档】
  • wordpress网站发布失败:此响应不是合法的JSON响应
  • 模版字符串复制粘贴支持换行
  • 【Block总结】TFF和SFF模块,时间和尺度的特征融合|即插即用
  • 【大数据2025】Yarn 总结
  • Android 11.0 第三方app接收不到开机广播问题的解决以及开机自启动功能实现二
  • Agent Laboratory: Using LLM Agents as Research Assistants 论文简介
  • 低代码系统-UI设计器核心介绍
  • MATLAB基础应用精讲-【数模应用】误差函数(erf)(附Java、python、R语言和MATLAB代码实现)
  • 高效安全文件传输新选择!群晖NAS如何实现无公网IP下的SFTP远程连接
  • Spring MVC:设置响应
  • Kafka 日志存储 — 文件目录及日志格式
  • Objective-C语言的数据库交互
  • goland map学习-实践使用练习:判断存在及遍历
  • 【计算机网络】传输层协议TCP与UDP
  • FreeRTOS系统移植
  • 在Vue中,<img> 标签的 src 值
  • 点云目标检测训练数据预处理---平面拟合与坐标转换(python实现)
  • MySQL事件功能简介
  • 【Web3企业出海】奇墨科技为企业出海提供云安全、ITQM智能运维及云MSP一站式服务
  • 数据分析及应用:经营分析中的综合指标解析与应用