Skip to content

useEffect如何清除副作用

Posted on:August 27, 2022

先引用官网给出的例子:

useEffect(() => {
  let ignore = false;

  async function startFetching() {
    const json = await fetchTodos(userId);
    if (!ignore) {
      setTodos(json);
    }
  }

  startFetching();

  return function clear() => {
    ignore = true;
  };
}, [userId]);

假设在组件的使用过程中,外部传入的 props 参数id,改变了两次,第一次传入 id: 1, 第二次传入 id: 2

那么我们来梳理一下整个过程:

1.传入props.id = 1

2.组件渲染

3.DOM 渲染完成,副作用逻辑执行,返回清除副作用函数clear,命名为clear1

4.传入props.id = 2

5.组件渲染

6.组件渲染完成,clear1 执行(注意此时 id 为 1 的请求结果还没有返回)

7.副作用逻辑执行(此时 clear1 执行后,ignore 变为 true,id 为 1 的请求还在 await,但因为 ignore 为 true 了,所以不会执行 setState,而是执行当前渲染的副作用函数内的请求,即 id 为 2,ignore 被重新赋值为 false),返回另一个 clear 函数,命名为clear2

8.组件销毁,clear2 执行

关键的地方就在于 clear 函数的执行:

进一步思考,clear1 执行的时候,访问了 props.id,那么这个 id 值是 1 还是 2 呢?

因为 useEffect 返回的是个函数,在执行时产生了一个闭包,根据闭包的相关定义,返回的 clear 函数能访问自身作用域外的变量,当组件第一次渲染时传入 id 是 1,此时的 clear 函数中的props.id值为 1。

通过 useEffect 的 clear 函数可以解决竞态问题(race conditions)