React useEffect 函数体和返回体的执行次数

useEffect 是 React 提供的一个 Hook,Hook 是 React 16.8 的新增特性,是一种复用 state 逻辑的方式,它让在函数组件使用 state 成为可能。useEffect 是一个常用的 Hook,用于在 React 更新 DOM 之后执行副作用,依赖的变化、生命周期的变化都会影响它的执行,本文通过实验验证它的具体行为。

useEffect 是啥

useEffect 是用来处理副作用的,那啥是副作用?发送网络请求、手动变更 DOM、记录日志这些与 React 更新 DOM 无关的操作都可算是副作用。
useEffect 可以看做是 componentDidMountcomponentDidUpdatecomponentWillUnmount 三个生命周期函数的组合。它接收的第一个参数是一个函数,这个函数用来执行副作用,下文称为函数体,函数体可以有一个函数作为其返回值,下文称为返回体,用来清除副作用。第二个可选参数接收一个数组,用来指定关注的依赖。

实验记录

我写了一个 demo 用来实验 useEffect 在依赖、生命周期发生变化时的执行情况。无依赖的情况是指不传入第二个参数,而空依赖是指传入一个空数组。

函数体

无依赖空依赖一个依赖两个依赖
进入页面执行一次执行一次执行一次执行一次
依赖发生变化组件状态发生变化就执行不执行对应依赖发生变化时执行一次至少一个依赖发生变化时执行一次
页面销毁不执行不执行不执行不执行

返回体

无依赖空依赖一个依赖两个依赖
进入页面不执行不执行不执行不执行
依赖发生变化组件状态发生变化就执行不执行对应依赖发生变化时执行一次至少一个依赖发生变化时执行一次
页面销毁执行一次执行一次执行一次执行一次

通过实验,可以知道几点结论:

  • 默认情况下(无依赖)useEffect 会在每次渲染后都执行,不管渲染是因为“挂载”还是“更新”导致的。
  • 空依赖下的 useEffectcomponentDidMountcomponentWillUnmount 的组合体,组件状态发生变化时,它并不执行。
  • 可以指定依赖来优化 useEffect 的执行次数,避免性能问题。
  • 多个依赖同时发生变化时,只会触发一次渲染,useEffect 也只会执行一次。
  • useEffect 会在调用一个新的 effect 之前对前一个 effect 进行清理,因此返回体只能拿到前一次的 state(需要拿最新的话可以考虑使用 useRef)。

参考资料