大家好,我是鱼樱!!!
关注公众号【鱼樱AI实验室】
持续每天分享更多前端和AI辅助前端编码新知识~~喜欢的就一起学反正开源至上,无所谓被诋毁被喷被质疑文章没有价值~~~坚持自己观点
写点笔记写点生活~写点经验。
在当前环境下,纯前端开发者可以通过技术深化、横向扩展、切入新兴领域以及产品化思维找到突破口。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
前置
生命周期一直是框架中的重要知识块之一,只有清楚了解每个阶段可以干什么的事情,才能精准控制代码的准确性
生命周期
生命周期:组件从诞生到销毁会经历一系列的过程,该过程就叫做生命周期。React在组件的生命周期中提供了一系列的钩子函数(类似于事件),可以让开发者在函数中注入代码,这些代码会在适当的时候运行。
生命周期仅存在于类组件中,函数组件每次调用都是重新运行函数,旧的组件即刻被销毁
旧版生命周期 (React < 16.0.0)
constructor
- 同一个组件对象只会创建一次
- 不能在第一次挂载到页面之前,调用setState,为了避免问题,构造函数中严禁使用setState
componentWillMount
- 正常情况下,和构造函数一样,它只会运行一次
- 可以使用setState,但是为了避免bug,不允许使用,因为在某些特殊情况下,该函数可能被调用多次
render
- 返回一个虚拟DOM,会被挂载到虚拟DOM树中,最终渲染到页面的真实DOM中
- render可能不只运行一次,只要需要重新渲染,就会重新运行
- 严禁使用setState,因为可能会导致无限递归渲染
componentDidMount
- 只会执行一次
- 可以使用setState
- 通常情况下,会将网络请求、启动计时器等一开始需要的操作,书写到该函数中
- 组件进入活跃状态
componentWillReceiveProps
- 即将接收新的属性值
- 参数为新的属性对象
- 该函数可能会导致一些bug,所以不推荐使用
shouldComponentUpdate
- 指示React是否要重新渲染该组件,通过返回true和false来指定
- 默认情况下,会直接返回true
componentWillUpdate
- 组件即将被重新渲染
componentDidUpdate
- 往往在该函数中使用dom操作,改变元素
componentWillUnmount
- 通常在该函数中销毁一些组件依赖的资源,比如计时器
新版生命周期 (React >= 16.0.0)
React官方认为,某个数据的来源必须是单一的
- getDerivedStateFromProps
- 通过参数可以获取新的属性和状态
- 该函数是静态的
- 该函数的返回值会覆盖掉组件状态
- 该函数几乎是没有什么用
- getSnapshotBeforeUpdate
- 真实的DOM构建完成,但还未实际渲染到页面中。
- 在该函数中,通常用于实现一些附加的dom操作
- 该函数的返回值,会作为componentDidUpdate的第三个参数
以下是React 16之前与之后生命周期的完整对比,结合新旧版本的差异与演进:
一、React 16之前(旧版)生命周期
1. 挂载阶段(Mounting)
constructor(props)
初始化state
和方法绑定。componentWillMount()
组件挂载前调用(服务器端渲染会触发),但存在副作用风险。render()
生成虚拟DOM结构,需保持纯净。componentDidMount()
DOM挂载完成后调用,用于网络请求、DOM操作。
2. 更新阶段(Updating)
componentWillReceiveProps(nextProps)
父组件传递新props
时触发(非首次)。shouldComponentUpdate(nextProps, nextState)
控制是否重新渲染,默认返回true
。componentWillUpdate(nextProps, nextState)
更新前调用,不可调用setState
。render()
重新生成虚拟DOM。componentDidUpdate(prevProps, prevState)
更新完成后执行副作用操作。
3. 卸载阶段(Unmounting)
componentWillUnmount()
清理定时器、取消订阅等资源释放。
特殊场景
- 强制更新:
this.forceUpdate()
跳过shouldComponentUpdate
直接触发更新。
二、React 16及之后(新版)生命周期
1. 挂载阶段(Mounting)
constructor(props)
同旧版。static getDerivedStateFromProps(props, state)
静态方法,替代componentWillReceiveProps
,根据props
派生state
。render()
未变化。componentDidMount()
同旧版。
2. 更新阶段(Updating)
static getDerivedStateFromProps(props, state)
同挂载阶段逻辑。shouldComponentUpdate(nextProps, nextState)
同旧版。render()
未变化。getSnapshotBeforeUpdate(prevProps, prevState)
新增方法,DOM更新前捕获信息(如滚动位置)。componentDidUpdate(prevProps, prevState, snapshot)
新增snapshot
参数接收捕捉的信息。
3. 卸载阶段(Unmounting)
componentWillUnmount()
同旧版。
4. 错误处理阶段(新增)
static getDerivedStateFromError(error)
捕获子组件错误并更新state
。componentDidCatch(error, info)
记录错误日志。
废弃的生命周期
componentWillMount
、componentWillReceiveProps
、componentWillUpdate
被标记为UNSAFE_
前缀。
三、新旧版本对比总结
特性 | React 16前 | React 16+ |
---|---|---|
挂载阶段 | 含componentWillMount | 废弃componentWillMount ,引入getDerivedStateFromProps |
更新阶段 | componentWillReceiveProps 触发更新 | 使用getDerivedStateFromProps 替代 |
DOM更新捕获 | 无 | 新增getSnapshotBeforeUpdate |
错误边界 | 无 | 新增getDerivedStateFromError 和componentDidCatch |
四、代码示例(新版)
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
static getDerivedStateFromProps(props, state) {
if (props.initialCount !== state.count) {
return { count: props.initialCount };
}
return null;
}
componentDidMount() {
// 初始化操作
}
getSnapshotBeforeUpdate(prevProps, prevState) {
return document.getElementById('list').scrollHeight;
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (snapshot !== null) {
// 使用快照值更新DOM
}
}
componentWillUnmount() {
// 清理资源
}
}
以上生命周期演进体现了React对副作用控制和异步渲染的优化方向,开发者应优先使用新API并避免废弃方法。
React 函数组件通过 Hooks API 模拟类组件的生命周期行为
React 函数组件通过 Hooks API 模拟类组件的生命周期行为,主要依赖于 useEffect
和 useLayoutEffect
实现不同阶段的逻辑管理。以下是函数组件生命周期的对应实现方式:
一、生命周期对应关系
1. 挂载阶段(Mounting)
-
组件初始化:
使用useState
初始化状态,类似类组件的constructor
。const [state, setState] = useState(initialValue);
-
DOM 挂载完成:
通过useEffect
的空依赖数组模拟componentDidMount
。useEffect(() => { // 网络请求、订阅或 DOM 操作 return () => { /* 卸载阶段的清理逻辑 */ }; }, []); // 空依赖数组确保仅执行一次
2. 更新阶段(Updating)
-
响应状态/属性变化:
useEffect
添加依赖项数组,模拟componentDidUpdate
。useEffect(() => { // 当 state 或 props 变化时执行 }, [state, props]); // 指定依赖项
-
DOM 更新前捕获信息:
使用useLayoutEffect
同步执行逻辑,类似getSnapshotBeforeUpdate
。useLayoutEffect(() => { // 同步获取 DOM 信息(如滚动位置) return () => { /* 清理逻辑 */ }; }, [dependencies]);
3. 卸载阶段(Unmounting)
- 资源清理:
在useEffect
中返回清理函数,模拟componentWillUnmount
。useEffect(() => { const timer = setInterval(() => {}, 1000); return () => clearInterval(timer); // 组件卸载时清理 }, []);
二、特殊场景与注意事项
1. 首次渲染与更新分离
- 使用
useRef
标记首次渲染,避免更新阶段逻辑在挂载时触发:const isMounted = useRef(false); useEffect(() => { if (!isMounted.current) { isMounted.current = true; // 初次渲染 } else { // 后续更新逻辑 } }, [dependencies]);
2. 同步副作用处理
useLayoutEffect
vsuseEffect
:useLayoutEffect
在 DOM 更新后同步执行,适合需要立即获取/修改 DOM 的场景。useEffect
异步执行,避免阻塞渲染流程。
三、完整示例代码
import { useState, useEffect, useLayoutEffect } from 'react';
function FunctionComponent(props) {
const [count, setCount] = useState(0);
// 模拟 componentDidMount
useEffect(() => {
console.log('组件挂载完成');
return () => console.log('组件卸载');
}, []);
// 模拟 componentDidUpdate(依赖 count)
useEffect(() => {
if (count > 0) console.log('count 更新:', count);
}, [count]);
// 同步获取 DOM 信息
useLayoutEffect(() => {
const element = document.getElementById('target');
if (element) console.log('元素高度:', element.offsetHeight);
});
return (
<div>
<button onClick={() => setCount(c => c + 1)}>点击 {count}</button>
<div id="target">内容区域</div>
</div>
);
}
四、与类组件对比总结
类组件生命周期 | 函数组件实现方式 |
---|---|
constructor | useState 初始化状态 |
componentDidMount | useEffect 空依赖数组 |
componentDidUpdate | useEffect 带依赖项数组 |
componentWillUnmount | useEffect 返回清理函数 |
getSnapshotBeforeUpdate | useLayoutEffect 同步操作 DOM |
五、最佳实践
- 避免滥用依赖项:精确指定依赖数组,防止无限循环。
- 优先异步副作用:默认使用
useEffect
,仅在必要时使用useLayoutEffect
。 - 逻辑复用:通过自定义 Hook 封装生命周期逻辑(如
useMount
、useUnmount
)。
函数组件的生命周期管理更简洁直观,但需注意 Hooks 的执行顺序和依赖管理规则。
React 生命周期是组件化开发的核心机制,其重要性体现在对组件行为的精细控制和开发效率的提升上。以下是关键原因:
生命周期的重要性
一、组件行为的可控性
-
精准调度不同阶段的逻辑
生命周期函数允许开发者在组件的初始化、更新、销毁等阶段注入逻辑,例如:- 挂载阶段初始化数据(如
constructor
初始化state
); - 更新阶段优化渲染(如
shouldComponentUpdate
跳过无效渲染); - 销毁阶段释放资源(如
componentWillUnmount
清理定时器)。
- 挂载阶段初始化数据(如
-
响应外部变化
通过getDerivedStateFromProps
或componentDidUpdate
,组件可动态适配props
变化或用户交互。
二、性能优化与资源管理
-
避免无效渲染
shouldComponentUpdate
可通过对比新旧props/state
阻止不必要的渲染,极大提升性能。 -
资源生命周期管理
确保异步操作(如网络请求、订阅事件)与组件生命周期同步,防止内存泄漏。
三、框架演进与最佳实践
-
适应异步渲染架构
React 16+ 废弃componentWillMount
等不安全方法,引入getSnapshotBeforeUpdate
,优先支持异步渲染模式下的稳定性和可预测性。 -
错误边界机制
新增的getDerivedStateFromError
和componentDidCatch
可捕获子组件错误,增强应用健壮性。
四、开发体验提升
-
调试与问题定位
明确的生命周期阶段划分,帮助开发者快速定位渲染异常或副作用问题(如数据更新未触发预期行为时,需检查componentDidUpdate
逻辑)。 -
代码可维护性
规范化的生命周期流程使组件逻辑更结构化,促进团队协作与代码复用。
总结
React 生命周期通过定义明确的组件阶段边界,为开发者提供了行为控制粒度、性能优化工具和错误处理机制。理解并合理运用这些函数,是构建高性能、可维护 React 应用的基础。