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

useEffect 是啥
useEffect 是用来处理副作用的,那啥是副作用?发送网络请求、手动变更 DOM、记录日志这些与 React 更新 DOM 无关的操作都可算是副作用。useEffect 可以看做是 componentDidMount、componentDidUpdate 和 componentWillUnmount 三个生命周期函数的组合。它接收的第一个参数是一个函数,这个函数用来执行副作用,下文称为函数体,函数体可以有一个函数作为其返回值,下文称为返回体,用来清除副作用。第二个可选参数接收一个数组,用来指定关注的依赖。
实验记录
我写了一个 demo 用来实验 useEffect 在依赖、生命周期发生变化时的执行情况。无依赖的情况是指不传入第二个参数,而空依赖是指传入一个空数组。
函数体
| 无依赖 | 空依赖 | 一个依赖 | 两个依赖 | |
|---|---|---|---|---|
| 进入页面 | 执行一次 | 执行一次 | 执行一次 | 执行一次 |
| 依赖发生变化 | 组件状态发生变化就执行 | 不执行 | 对应依赖发生变化时执行一次 | 至少一个依赖发生变化时执行一次 |
| 页面销毁 | 不执行 | 不执行 | 不执行 | 不执行 |
返回体
| 无依赖 | 空依赖 | 一个依赖 | 两个依赖 | |
|---|---|---|---|---|
| 进入页面 | 不执行 | 不执行 | 不执行 | 不执行 |
| 依赖发生变化 | 组件状态发生变化就执行 | 不执行 | 对应依赖发生变化时执行一次 | 至少一个依赖发生变化时执行一次 |
| 页面销毁 | 执行一次 | 执行一次 | 执行一次 | 执行一次 |
通过实验,可以知道几点结论:
- 默认情况下(无依赖)
useEffect会在每次渲染后都执行,不管渲染是因为“挂载”还是“更新”导致的。 - 空依赖下的
useEffect是componentDidMount和componentWillUnmount的组合体,组件状态发生变化时,它并不执行。 - 可以指定依赖来优化
useEffect的执行次数,避免性能问题。 - 多个依赖同时发生变化时,只会触发一次渲染,
useEffect也只会执行一次。 useEffect会在调用一个新的 effect 之前对前一个 effect 进行清理,因此返回体只能拿到前一次的state(需要拿最新的话可以考虑使用useRef)。