跳到主要内容

用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,比按生命周期分更稳。