
使用 useEffect 配合空依赖数组,可在组件挂载后执行初始化(如读取 URL/本地存储),并在卸载前执行清理(如持久化最新状态);useMemo 不适用于生命周期钩子,它仅用于性能优化的值缓存。
使用 `useeffect` 配合空依赖数组,可在组件挂载后执行初始化(如读取 url/本地存储),并在卸载前执行清理(如持久化最新状态);`usememo` 不适用于生命周期钩子,它仅用于性能优化的值缓存。
在 React 函数组件中,没有名为“组件出生”或“死亡”的显式生命周期方法,但可通过 useEffect 精确模拟这一行为:其回调函数在组件首次挂载(DOM 插入)后执行,而其返回的清理函数则在组件即将卸载(DOM 移除)前调用。
✅ 正确做法:统一使用 useEffect
import { useEffect, useState } from 'react';
function FilterableList() {
const [filters, setFilters] = useState({});
useEffect(() => {
// ✅ 组件“出生”:仅在挂载后执行一次
// 从 URL 查询参数或 localStorage 加载初始过滤器
const urlParams = new URLSearchParams(window.location.search);
const savedFilters = localStorage.getItem('listFilters');
const initial = {
...Object.fromEntries(urlParams),
...(savedFilters ? JSON.parse(savedFilters) : {}),
};
setFilters(initial);
// ✅ 组件“死亡”:清理函数在卸载前执行
return () => {
// 将当前最新 filters 持久化到 localStorage
localStorage.setItem('listFilters', JSON.stringify(filters));
};
}, []); // ? 空依赖数组确保只运行一次
// 后续可监听 filters 变化并同步更新 URL(例如通过 useNavigate 或 history.push)
useEffect(() => {
const params = new URLSearchParams(filters);
window.history.replaceState(null, '', `?${params}`);
}, [filters]);
return <div>/* 渲染列表与筛选控件 */</div>;
}
❌ 常见误区辨析:
-
useMemo(() => { ... }, [])❌:它仅用于缓存计算结果,不保证执行时机(可能被 React 延迟或跳过),且无清理机制,无法响应组件卸载。 -
useEffect(() => { ... }, [])✅:语义明确、时机可控、支持清理函数,是官方推荐的替代componentDidMount+componentWillUnmount的标准方案。
⚠️ 注意事项:
- 清理函数中访问的
filters是闭包捕获的挂载时的状态快照,若需最新值,应结合useRef缓存或在清理前显式读取(如localStorage.setItem(..., JSON.stringify(filtersRef.current))); - 若组件可能被 Suspense 或错误边界中断,清理函数仍会被可靠调用;
- 确保依赖数组严格为空
[]—— 即使写成[undefined]或[null]都会导致意外重执行。
总结:对于“仅在挂载时执行一次 + 卸载前清理”的需求,useEffect 是唯一兼具语义清晰性、执行确定性与资源安全性的选择。将初始化与清理逻辑置于同一 useEffect 块中,既符合 React 的设计哲学,也便于维护和测试。











