在 React 中,类组件通过 componentDidMount、componentDidUpdate、componentWillUnmount 等方法管理生命周期,而函数组件则通过 Hooks 实现类似的生命周期逻辑,其中最核心的是 useEffect。
Taimili 艾米莉 ( 一款免费开源的 taimili.com )
艾米莉 是一款优雅便捷的** GitHub Star 管理和加星工具**,基于 PHP & javascript 构建, 能对github 的 star fork follow watch 管理和提升,最适合github 的深度用户
核心逻辑:Hooks 如何映射生命周期?
函数组件没有类组件那样的「生命周期方法」,而是通过 副作用(Side Effect) 来处理生命周期相关的逻辑(如数据请求、订阅、DOM 操作等)。useEffect 是处理副作用的主要 Hook,它可以模拟类组件的多个生命周期阶段。
1. 挂载阶段(Mount):组件首次渲染完成
对应类组件的 componentDidMount,即组件首次渲染到 DOM 后执行的逻辑(如初始化数据请求、事件监听等)。
实现方式:useEffect 传入一个副作用函数,第二个参数传空依赖数组 [] ,表示该副作用只在组件挂载时执行一次。
jsx
useEffect(() => {
// 组件挂载时执行(类似 componentDidMount)
console.log("组件挂载完成");
// 示例:发起初始化请求
fetchData();
}, []); // 空依赖数组 → 只在挂载时执行
2. 更新阶段(Update):组件重新渲染
对应类组件的 componentDidUpdate,即组件因 props 或 state 变化重新渲染后执行的逻辑(如根据新 props 重新请求数据)。
实现方式:
-
若
useEffect不传入第二个依赖参数,则每次组件渲染(包括首次和更新)后都会执行,相当于componentDidMount + componentDidUpdate。 -
若传入非空依赖数组
[dep1, dep2],则只有当依赖项(dep1、dep2)发生变化时,才会在更新后执行。
jsx
// 1. 每次渲染后都执行(不推荐,可能导致性能问题)
useEffect(() => {
console.log("组件渲染/更新完成");
});
// 2. 只有当 count 变化时,才在更新后执行(类似 componentDidUpdate)
useEffect(() => {
console.log(`count 变为 ${count},执行更新逻辑`);
// 示例:根据新的 count 请求数据
fetchDataByCount(count);
}, [count]); // 依赖 count → 仅 count 变化时执行
3. 卸载阶段(Unmount):组件从 DOM 中移除
对应类组件的 componentWillUnmount,即组件卸载前需要清理的逻辑(如取消订阅、清除定时器、取消请求等)。
实现方式:useEffect 的副作用函数可以返回一个「清理函数」,该函数会在组件卸载时执行,也会在「下一次副作用执行前」执行(避免残留副作用)。
jsx
useEffect(() => {
// 挂载时执行:开启定时器
const timer = setInterval(() => {
console.log("定时器执行中...");
}, 1000);
// 返回清理函数(卸载时执行)
return () => {
// 组件卸载时清理:清除定时器
clearInterval(timer);
console.log("组件卸载,清理完成");
};
}, []); // 空依赖 → 清理函数仅在卸载时执行
其他 Hooks 与生命周期的关联
useLayoutEffect:与useEffect用法完全一致,但执行时机不同。useLayoutEffect在 DOM 更新同步完成后立即执行(阻塞渲染),而useEffect在 DOM 更新后异步执行(不阻塞渲染)。适合需要立即操作 DOM 并获取布局信息的场景(类似componentDidMount的同步版本)。useMemo/useCallback:用于缓存计算结果或函数,避免不必要的重复计算 / 创建,间接优化更新阶段的性能(类似shouldComponentUpdate的部分功能,但逻辑不同)。
总结:Hooks 生命周期的核心特点
-
统一抽象:用
useEffect统一处理挂载、更新、卸载的副作用逻辑,替代类组件中多个生命周期方法的分散实现。 -
依赖驱动:通过依赖数组精确控制副作用的执行时机,减少不必要的重复执行。
-
清理机制:内置清理函数,自动处理副作用的「收尾工作」,避免内存泄漏。
这种设计让函数组件的逻辑组织更灵活,尤其在处理多个独立副作用时(如同时管理定时器和数据订阅),比类组件的生命周期方法更清晰。