React 生命周期完整指南
React 生命周期完整指南
1. 生命周期概述
1.1 React 16.3 之前的生命周期
- 初始化阶段
- constructor
- componentWillMount
- render
- componentDidMount
- 更新阶段
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
- 卸载阶段
- componentWillUnmount
1.2 React 16.3 之后的生命周期
- 初始化阶段
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
- 更新阶段
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
- 卸载阶段
- componentWillUnmount
2. 详细说明
2.1 挂载阶段
class MyComponent extends React.Component {// 1. 构造函数constructor(props) {super(props);this.state = {count: 0};console.log('1. constructor');}// 2. 派生状态static getDerivedStateFromProps(props, state) {console.log('2. getDerivedStateFromProps');return null;}// 3. 渲染render() {console.log('3. render');return <div>{this.state.count}</div>;}// 4. 挂载完成componentDidMount() {console.log('4. componentDidMount');}
}
2.2 更新阶段
class UpdateComponent extends React.Component {// 1. 派生状态static getDerivedStateFromProps(props, state) {console.log('1. getDerivedStateFromProps');return null;}// 2. 是否应该更新shouldComponentUpdate(nextProps, nextState) {console.log('2. shouldComponentUpdate');return true;}// 3. 渲染render() {console.log('3. render');return <div>{this.state.count}</div>;}// 4. 获取更新前的快照getSnapshotBeforeUpdate(prevProps, prevState) {console.log('4. getSnapshotBeforeUpdate');return null;}// 5. 更新完成componentDidUpdate(prevProps, prevState, snapshot) {console.log('5. componentDidUpdate');}
}
2.3 卸载阶段
class UnmountComponent extends React.Component {componentWillUnmount() {console.log('componentWillUnmount');// 清理工作:取消订阅、清除定时器等}
}
3. 新旧生命周期对比
3.1 被移除的生命周期方法
componentWillMount
// 旧版本
componentWillMount() {// 组件即将挂载// 问题:可能会导致服务器端渲染问题
}// 新版本替代方案
componentDidMount() {// 组件已挂载// 建议在这里进行异步操作
}
componentWillReceiveProps
// 旧版本
componentWillReceiveProps(nextProps) {// 即将接收新的 propsif (nextProps.value !== this.props.value) {this.setState({ value: nextProps.value });}
}// 新版本替代方案
static getDerivedStateFromProps(props, state) {if (props.value !== state.value) {return { value: props.value };}return null;
}
componentWillUpdate
// 旧版本
componentWillUpdate(nextProps, nextState) {// 即将更新// 问题:可能会导致异步渲染问题
}// 新版本替代方案
getSnapshotBeforeUpdate(prevProps, prevState) {// 获取更新前的快照return null;
}
3.2 新增的生命周期方法
getDerivedStateFromProps
class Example extends React.Component {static getDerivedStateFromProps(props, state) {// 返回新状态或 nullif (props.currentRow !== state.lastRow) {return {isScrollingDown: props.currentRow > state.lastRow,lastRow: props.currentRow};}return null;}
}
getSnapshotBeforeUpdate
class ScrollingList extends React.Component {getSnapshotBeforeUpdate(prevProps, prevState) {// 捕获更新前的信息if (prevProps.list.length < this.props.list.length) {const list = this.listRef.current;return list.scrollHeight - list.scrollTop;}return null;}componentDidUpdate(prevProps, prevState, snapshot) {// 使用快照信息if (snapshot !== null) {const list = this.listRef.current;list.scrollTop = list.scrollHeight - snapshot;}}
}
4. 生命周期最佳实践
4.1 常见用途
class BestPractices extends React.Component {constructor(props) {super(props);// 初始化状态// 绑定方法}static getDerivedStateFromProps(props, state) {// 用于状态的派生// 不要在这里执行副作用return null;}componentDidMount() {// 适合执行副作用// - 网络请求// - DOM 操作// - 订阅}shouldComponentUpdate(nextProps, nextState) {// 性能优化// 返回 false 可以阻止更新return true;}getSnapshotBeforeUpdate(prevProps, prevState) {// 获取 DOM 更新前的信息return null;}componentDidUpdate(prevProps, prevState, snapshot) {// 更新后的操作// 可以执行副作用// 注意避免无限循环}componentWillUnmount() {// 清理工作// - 取消订阅// - 清除定时器// - 取消网络请求}
}
4.2 错误处理
class ErrorBoundary extends React.Component {state = { hasError: false };static getDerivedStateFromError(error) {// 更新状态,下次渲染时显示降级 UIreturn { hasError: true };}componentDidCatch(error, errorInfo) {// 记录错误信息console.error('Error:', error);console.error('Error Info:', errorInfo);}render() {if (this.state.hasError) {return <h1>Something went wrong.</h1>;}return this.props.children;}
}
5. Hooks 时代的生命周期
5.1 使用 Hooks 模拟生命周期
function HooksLifecycle() {// 模拟 constructorconst [state, setState] = useState({count: 0});// 模拟 componentDidMountuseEffect(() => {console.log('Component mounted');return () => {// 模拟 componentWillUnmountconsole.log('Component will unmount');};}, []);// 模拟 componentDidUpdateuseEffect(() => {console.log('State updated:', state);}, [state]);return <div>{state.count}</div>;
}
5.2 生命周期方法与 Hooks 对照表
| 生命周期方法 | Hooks 实现 |
|---|---|
| constructor | useState |
| componentDidMount | useEffect(() => {}, []) |
| componentDidUpdate | useEffect(() => {}, [deps]) |
| componentWillUnmount | useEffect(() => { return () => {} }, []) |
| shouldComponentUpdate | useMemo, useCallback |
| getDerivedStateFromProps | useState + useEffect |
6. 总结
6.1 生命周期选择建议
- 使用
componentDidMount进行初始化操作 - 使用
componentDidUpdate响应更新 - 使用
componentWillUnmount清理资源 - 优先考虑新的生命周期方法
- 在合适的场景使用 Hooks
6.2 注意事项
- 避免在构造函数中执行副作用
- 不要在
getDerivedStateFromProps中执行副作用 - 谨慎使用
shouldComponentUpdate - 在
componentDidUpdate中注意避免无限循环 - 确保在
componentWillUnmount中清理所有副作用
6.3函数组件中的生命周期(通过 Hooks)
useEffect 可以模拟 componentDidMount 和 componentDidUpdate,通过将依赖项传递给 useEffect 来控制副作用的执行。传递空数组 [] 作为依赖项时,useEffect 只会在组件首次挂载时执行,相当于 componentDidMount。
清理副作用:useEffect 可以返回一个清理函数,相当于类组件中的 componentWillUnmount。
import React, { useState, useEffect } from 'react';const MyFunctionComponent = () => {const [counter, setCounter] = useState(0);// 模拟 componentDidMount 和 componentDidUpdateuseEffect(() => {console.log('组件已挂载或更新');// 模拟 componentWillUnmountreturn () => {console.log('组件将卸载');};}, [counter]); // 依赖项,只有当 counter 更新时,才会重新执行 useEffectreturn (<div><p>Counter: {counter}</p><button onClick={() => setCounter(counter + 1)}>增加计数</button></div>);
};export default MyFunctionComponent;
6.4 React 18 的新特性
React 18 引入了多个新特性,最显著的之一是 并发模式(Concurrent Mode),它改善了渲染性能,尤其是在 React 应用的响应式方面。虽然并发模式与生命周期方法的直接关系不大,但它会影响组件的挂载、更新和卸载过程。
React 18 还引入了 自动批量更新(Automatic Batching)和 Suspense 进一步增强了异步渲染的能力。这些新特性和生命周期方法并没有冲突,而是增强了现有的机制。
总结:
类组件:React 18 中,类组件的生命周期方法仍然有效,且与之前的版本一样。
函数组件:函数组件使用 useEffect 和其他 Hooks 来模拟传统的生命周期方法。
React 18 新特性:引入了并发模式、自动批量更新等,但它不会影响生命周期方法。
因此,如果你使用类组件,React 18 中依然可以使用传统的生命周期方法。如果使用函数组件,你可以通过 useEffect 来替代和模拟传统生命周期的行为。
相关文章:
React 生命周期完整指南
React 生命周期完整指南 1. 生命周期概述 1.1 React 16.3 之前的生命周期 初始化阶段 constructorcomponentWillMountrendercomponentDidMount 更新阶段 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 卸载阶段 componentWil…...
python中os._exit(0) 强制关闭进程后来杀死线程
在 Python 中调用 os._exit(0) 会强制终止整个进程,包括所有正在运行的线程。以下是详细解释: os._exit(0) 的行为 立即终止进程:os._exit() 函数会立即终止当前进程,不会执行任何清理操作,如调用清理处理程序&#…...
LeetCode:257. 二叉树的所有路径
跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:257. 二叉树的所有路径 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根…...
RSICV国产芯片之CHV208
1. 芯片选型分析的对比维度 分析或者对标应用的芯片替代思路 1.1 内核/主频/存储空间支持 内核能力/指令集支持(考虑工具链兼容性); 主频:对比计算能力是否满足基本要求 存储:内存--数据搬移空间决定数据运算的…...
理解神经网络
神经网络是一种模拟人类大脑工作方式的计算模型,是深度学习和机器学习领域的基础。 基本原理 神经网络的基本原理是模拟人脑神经系统的功能,通过多个节点(也叫神经元)的连接和计算,实现非线性模型的组合和输出。每个…...
Android 之 List 简述
一、简单创建方式 Android 开发中,列表有很多种类,如ArrayList、LinkedList、List、MutableList等,创建列表的方式如下所示: fun listDemo() {// 使用 listOf 创建不可变的空列表val list listOf<Int>()val list1 listOf…...
设计模式の中介者发布订阅备忘录模式
文章目录 前言一、中介者模式二、发布订阅模式三、备忘录模式 前言 本篇是关于设计模式中介者模式、观察者(发布-订阅)模式、以及备忘录模式的学习笔记。 一、中介者模式 中介者模式是一种行为型设计模式,其核心目的是为了减少对象之间的复杂…...
云手机群控能用来做什么?
随着云手机的发展,云手机群控技术逐渐从小众的游戏多开工具,发展为涵盖多个领域的智能操作平台。不论是手游搬砖、短视频运营,还是账号养成等场景,云手机群控都展现出了强大的应用潜力。本文将为大家详细解析云手机群控的应用场景…...
fpgafor循环语句使用
genvar i;//循环变量名称 generate for(i0;i<4;ii1)begin:tx//自己定义名称 //循环内容 end endgenerate12位的16进制乘以4就是48位位宽的2进制 因为 222*2(2^4)16...
【FastAPI】BaseHTTPMiddleware类
一、概述 在FastAPI中,BaseHTTPMiddleware 类是Starlette框架提供的一个抽象基类,它允许开发者基于HTTP请求/响应接口编写ASGI中间件。 这个类对于希望实现自定义中间件逻辑的开发者来说是非常重要的工具。 通过继承 BaseHTTPMiddleware 并实现特定的方…...
Solon v3.0.5 发布!(Spring 可以退休了吗?)
Solon 框架! 新一代,面向全场景的 Java 应用开发框架。从零开始构建(非 java-ee 架构),有灵活的接口规范与开放生态。 追求: 更快、更小、更简单提倡: 克制、高效、开放、生态 有什么特点&am…...
网络安全攻防演练中的常见计策
大家觉得有意义记得关注和点赞!!! 引言 在网络安全攻防演练里面,用于分析攻击者动机和行为的,国外的有基于攻击链分析的模型(如Cyber Kill Chain和ATT&CK)和基于威胁行为的模型(…...
SD卡模块布局布线设计
1、SD/TF/SIM卡的定义 2、SD/TF/SIM卡模块引脚定义以及图示 3、SD/TF/SIM卡接口布局和布线 4、小结 1、BGA两线交叉时,可以在源头将两线互相短路连接,然后再输出口删除一小节线,然后CHRLX/V,这样就可以换两条线的网络,…...
Flask-----SQLAlchemy教程
存session session[username] username # 存储数据到 session 取session username session.get(username) render_template return render_template(index.html, usernameAlice),渲染一个包含 username 变量的模板。 redirect return redirect(url_for(profil…...
STM32 高级 物联网通信之CAN通讯
目录 CAN通讯介绍 物理层 协议层 CAN的帧(报文)种类 1 数据帧(发送单元->接受单元) 2 远程帧(接受单元->发送单元) 3 错误帧(发送方发送数据错误会发送的状态帧) 4 过载帧(接收方放不下会发送到的状态帧) 5 帧间隔(状态) 数据帧介绍 远程帧介绍 C…...
“乡村探索者”:村旅游网站的移动应用开发
3.1 可行性分析 从三个不同的角度来分析,确保开发成功的前提是有可行性分析,只有进行提前分析,符合程序开发流程才不至于开发过程的中断。 3.1.1 技术可行性 在技术实现层次,分析了好几种技术实现方法,并且都有对应的成…...
前端案例---自定义鼠标右键菜单
之前右击出现默认的选项菜单,使用evt.preventDefault()把默认的去掉,然后自定义右击的样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible"…...
浅谈归一化
在深度学习中,对网络层进行归一化(Normalization,简称Norm)是一个重要的技巧。常见的归一化方法包括批归一化(Batch Normalization)、层归一化(Layer Normalization)、实例归一化&am…...
lodash常用函数
文章目录 一、数组1、chunk分组2、difference、differenceBy、differenceWith3、findIndex4、intersection、intersectionBy、intersectionWith5、union、unionBy、unionWith 二、对象1、pick、omit 2、get、set三、数学1、sum、sumBy2、range 四、工具函数1、isEqual、isEmpty…...
触控算法总结
一、触控湿手指算法的具体实现原理涉及多个方面的技术和方法,主要包括以下几个关键点 1.电容变化检测 电容式触摸屏通过检测电容变化来确定触摸位置。当手指接触屏幕时,会引起电容的变化。然而,当手指湿润时,水分会影响电容值,导致触摸屏误判成无法正确识别触控点 2.噪声过滤: …...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
