React 的生命周期指的是组件在创建、更新和销毁的整个过程。在 React 的类组件中,生命周期分为三个主要阶段:
- 挂载(Mounting)
- 更新(Updating)
- 卸载(Unmounting)
如果使用的是函数组件,生命周期是通过 useEffect
以及其他 Hooks 来管理的。
1. 挂载阶段(Mounting)
组件被创建并插入到 DOM 中的阶段。
在类组件中,会触发以下方法:
constructor()
static getDerivedStateFromProps(props, state)
render()
componentDidMount()
详细介绍:
constructor(props)
- 组件初始化时调用,用于设置初始状态
state
或绑定this
。 - ⚠️ 不要在这里执行异步操作,适合用于基本的初始化。
- 组件初始化时调用,用于设置初始状态
static getDerivedStateFromProps(props, state)
- 在
render
之前触发,用于根据props
更新state
,但不常用。 - ⚠️ 这是一个静态方法,不能使用
this
!
- 在
render()
- 组件渲染 UI,必须是纯函数,不能有副作用(如异步请求)。
componentDidMount()
- 组件挂载后调用,通常用于发送网络请求、订阅事件、操作 DOM 等。
- 适合执行副作用操作(如
setTimeout
、setInterval
等)。
componentDidMount() { fetch("/api/data") .then(response => response.json()) .then(data => this.setState({ data })); }
2. 更新阶段(Updating)
组件的 state
或 props
发生变化时,触发更新。
会调用以下方法:
static getDerivedStateFromProps(props, state)
shouldComponentUpdate(nextProps, nextState)
render()
getSnapshotBeforeUpdate(prevProps, prevState)
componentDidUpdate(prevProps, prevState, snapshot)
详细介绍:
shouldComponentUpdate(nextProps, nextState)
- 返回
true
组件才会重新渲染,false
则阻止更新,提高性能。 - 适用于优化性能,防止不必要的重渲染。
- 返回
render()
- UI 重新渲染。
getSnapshotBeforeUpdate(prevProps, prevState)
- 组件更新前的“快照”,常用于获取 DOM 变化前的信息(如滚动位置)。
- 返回值会传递给
componentDidUpdate()
。
componentDidUpdate(prevProps, prevState, snapshot)
- 组件更新完成后执行,适合发送异步请求、更新 DOM。
- ⚠️ 需要注意避免死循环!
- 例如:
componentDidUpdate(prevProps) { if (this.props.userId !== prevProps.userId) { this.fetchUserData(); } }
3. 卸载阶段(Unmounting)
组件被从 DOM 中移除时触发。
只有一个方法:
componentWillUnmount()
详细介绍:
componentWillUnmount()
- 组件销毁前调用,适用于清理副作用,如:
- 清除
setInterval
、setTimeout
- 取消 API 请求
- 移除事件监听
- 清除
componentWillUnmount() { clearInterval(this.timer); }
- 组件销毁前调用,适用于清理副作用,如:
⚛️ 在函数组件中,如何使用生命周期?
React 提供了 useEffect
来代替生命周期方法:
import { useEffect, useState } from "react";
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount + componentDidUpdate
useEffect(() => {
console.log("组件挂载或更新了!");
return () => {
console.log("组件即将卸载!");
};
}, [count]); // 只有 count 变化时才会触发
return <button onClick={() => setCount(count + 1)}>点击 {count}</button>;
}
useEffect(() => {}, [])
:只在组件挂载时运行(等价于componentDidMount
)。useEffect(() => {}, [变量])
:当变量
变化时运行(等价于componentDidUpdate
)。useEffect(() => { return () => {} }, [])
:组件卸载时运行(等价于componentWillUnmount
)。
前端哪些功能需要关注生命周期?
(一些涉及到内存泄漏的问题)
- 网络请求
componentDidMount()
/useEffect(() => {}, [])
:- 组件加载时请求数据,如用户信息、列表数据。
- 事件监听
componentDidMount()
/useEffect(() => {... return () => {...} }, [])
:- 监听键盘事件、窗口大小变化。
- 在
componentWillUnmount()
中移除监听 避免内存泄漏。
useEffect(() => { window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []);
- 定时器
componentDidMount()
/useEffect(() => {... return () => {...} }, [])
:setInterval
/setTimeout
需要在componentWillUnmount()
里清除。
- DOM 操作
useEffect(() => {}, [])
- 获取滚动位置、测量元素大小。
- 性能优化
shouldComponentUpdate()
/React.memo()
- 防止组件不必要的重新渲染。
总结
生命周期阶段 | 类组件方法 | 函数组件 Hook |
---|---|---|
挂载 | componentDidMount() |
useEffect(() => {...}, []) |
更新 | componentDidUpdate(prevProps, prevState) |
useEffect(() => {...}, [依赖]) |
卸载 | componentWillUnmount() |
useEffect(() => { return () => {...} }, []) |
如果你用的是函数组件,大部分生命周期操作都可以通过 useEffect
处理。