DrillLab
第 61 / 105 道61 / 105 · #325

useEffect 和生命周期怎么对应

UseEffect vs Lifecycle Methods

先自己答,再往下看Answer it yourself first

一句话(这句要说准):useEffect不是生命周期的替代品,它是「同步副作用」的另一种思路—— 你声明「这个副作用依赖哪些值」,值变了它就重新跑。

类组件useEffect 写法
componentDidMountuseEffect(fn, [])
componentDidUpdateuseEffect(fn, [dep])
componentWillUnmounteffect 里 return () => {}
三个都要useEffect(fn)(不写依赖数组)
在 componentDidMount / componentDidUpdate 里同步测量 DOM 再改样式useLayoutEffect(DOM 更新后、浏览器绘制前同步执行)

但这张表有个陷阱——useEffect(fn, [])不完全等于 componentDidMount:前者在浏览器绘制之后异步执行,后者是同步的。所以用 useEffect测量 DOM 再改样式会闪一下,这种情况要用useLayoutEffect。
getSnapshotBeforeUpdate 目前没有对应的 hook,真要用只能写类组件。

更重要的是别用生命周期的思维写 effect。正确的问法不是「我要在挂载时干什么」,而是「这个副作用依赖哪些值」。依赖列全,React 自然会在该跑的时候跑。

会追问:「清理函数什么时候执行?」——依赖变化前和卸载时。我们那道计时器变式题就是这个考点:漏了 clearInterval,start/pause 四次会得到 10 秒而不是 4 秒(实测)。

In one line — say this precisely: useEffect is not a replacement for lifecycle methods; it is a different way of thinking about synchronising side effects — you declare which values a side effect depends on, and it re-runs when they change.

Class componentuseEffect form
componentDidMountuseEffect(fn, [])
componentDidUpdateuseEffect(fn, [dep])
componentWillUnmountreturn () => {} inside the effect
All three at onceuseEffect(fn) (no dependency array)
Measuring the DOM synchronously in componentDidMount / componentDidUpdate and then restylinguseLayoutEffect (runs synchronously after the DOM updates, before the browser paints)

But the table has a trap — useEffect(fn, []) is not quite componentDidMount: the first runs asynchronously after the browser paints, the second is synchronous. So measuring the DOM in a useEffect and then changing styles will flash; that case wants useLayoutEffect.
getSnapshotBeforeUpdate has no Hook equivalent yet; if you really need it, you still write a class component.

More important: stop writing effects with a lifecycle mindset. The right question is not “what do I do on mount” but “which values does this side effect depend on”. List the dependencies properly and React runs it when it should.

Follow-up: “When does the cleanup function run?” — before the dependencies change and on unmount. Our timer variant question tests exactly this: drop the clearInterval and four start/pause rounds give you 10 seconds instead of 4 (measured).