用useEffect模拟Class Component的生命周期

828 阅读2分钟

引言

Function Component 不存在生命周期,不要把 Class Component 的生命周期概念搬过来试图对号入座。Function Component只有一个状态用来描述 UI 状态,React 会将其同步到 DOM,仅此而已。

React Hooks的出现扩展了function component的用法,官方要求开发者要改变使用react的心智,要求开发者忘记react的生命周期,但是开发者确实有用到生命周期的场景。怎么办呢?通过一些固定用法可以模拟Class component的生命周期形式。

模拟 componentDidMount

直接说结果:

useEffect(fn, [])

上面会保证Function Component组件首次渲染完毕后,只执行一次回调。原因:

useEffect第二个参数为[], react认为该effect不参与react的数据流中,所以只执行一次。

虽然用法上与react的componentDidMount生命周期相似,但是二者不是完全等同。 与componentDidMount不同的是,当前的effect回调中捕获的propsstate值是初始值,不能捕获二者最新的值,若想捕获最新的值,需要使用useRef来配合。

模拟 componentDidUpdate

直接上结果:

useEffect(fn)

useEffect不传第二个参数,那么在每次组件重新更新渲染时回调都会执行一次。

或者监听指定的某些状态改变时执行对应的回调,即:

useEffect(fn, [state1, state2, ...])

这种方式只有useEffect依赖的状态改变时才会执行对于回调,初次之外的其他状态改变不会执行该effect。

补充一点:

useEffect的第二种方式中,回调中使用的状态都需要通过第二个参数告诉react,否则该状态值改变其回调也不会执行。

模拟 componentWillUnmount

直接上结果:

useEffect(() => {
    return () => {} // 返回的函数类似于componentWillUnmount
}, [])

useEffect回调函数返回的函数类似于react的componentWillUnmount生命周期,在组件销毁时执行。

注意,上面useEffect函数的第二个参数为空数组[],这样它不参与react的数据流,所以只执行一次,在组件销毁时执行一次。

注意坑点:

useEffect在不传或者传递第二个参数不为空数组时,其回调返回的函数会在每次组件更新或者指定的依赖变更时都会执行一次。

例如:

useEffect(() => {
    return () => {
        console.log('每次更新我都会被调用');
    } 
})

这会导致组件每次更新这个返回函数都会调用。

另一种情况:

useEffect(() => {
    return () => {
        console.log('state1或state2每次更新我都会被调用');
    } 
}, [state1, state2])

这种情况再其依赖项每次变更时返回函数都会被调用。

很显然,上面两种情况不是我们想要的componentWillUnmount时机点。

参考

1、精读《useEffect 完全指南》

2、A Complete Guide to useEffect