用useEffect模拟组件生命周期
面试速答
- 以下内容以 React 18 为准。
useEffect可以在语义上近似模拟部分生命周期,但 不能机械地把 Hooks 理解成 class 生命周期一一映射。- 更准确的说法是:
useEffect用来在提交后同步副作用。
常见映射方式
1. 模拟 componentDidMount
useEffect(() => {
console.log('挂载后执行')
}, [])
它语义上接近“首次挂载后执行”,但 React 18 开发环境 StrictMode 下可能会多执行一轮挂载清理检查。
2. 模拟 componentDidUpdate
useEffect(() => {
console.log('依赖变化后执行')
}, [userId, keyword])
依赖变化时重新执行,语义上接近更新后逻辑。
3. 模拟 componentWillUnmount
useEffect(() => {
return () => {
console.log('卸载时清理')
}
}, [])
cleanup 会在卸载时执行。
为什么说只是“近似模拟”
因为 useEffect 的设计目标不是复制旧生命周期,而是:
- 把副作用和某些依赖值同步起来
- 在下一次 effect 前或卸载时清理
所以它比 class 生命周期更强调“依赖关系”,不是“时间点名称”。
更稳的理解方式
1. 按职责拆 effect
不要写成:
useEffect(() => {
fetchData()
bindResize()
document.title = title
return () => unbindResize()
}, [title, userId])
这种 effect 依赖会越来越乱。
更推荐拆成多个 effect,各自只做一类同步。
2. 不要用 effect 模拟所有生命周期需求
很多逻辑其实不该进 effect,比如:
- 纯计算
- 基于当前 props/state 派生数据
- 事件触发时的即时逻辑
标准答法
问:如何用 useEffect 模拟生命周期?
答:useEffect(() => {}, []) 近似挂载后执行,useEffect(() => {}, [deps]) 近似依赖更新后执行,useEffect(() => () => {}, []) 的 cleanup 近似卸载清理。但 React 18 下不能把它机械等同于 class 生命周期。
易错点
- 把
useEffect([])绝对等同于componentDidMount。 - 忘记开发环境双执行。
- 把所有逻辑都塞进一个大 effect。
速记要点
useEffect是副作用同步机制,不是生命周期翻译器。- 可以近似模拟,但别机械映射。
- 按职责拆 effect,比按生命周期分更稳。