React Hook: useEffect清理副作用的意义和处理探索

本文主要介绍对useEffect中清理副作用的思考,并提供部分处理案例。

起因

我在读react hook文档的时候,读到一个章节叫做“需要清除的 effect”。其中提到“……还有一些副作用是需要清除的。例如订阅外部数据源。这种情况下,清除工作是非常重要的,可以防止引起内存泄露!……”。

订阅外部数据源我貌似明白,但是从来没听过需要清理什么东西,所以我对订阅外部数据源产生了疑惑。后来在微信群中询问,没有人回复。只好自己查了。

理解

我最终的理解是,在做异步操作的时候,被打断了。一般打断不要紧,关键这个打断影响了后面语句的执行。这时候,需要做一个突然被打断的考虑。也就是文档中提到的防止引起内存泄漏。

典型场景可能有三个:

  1. 异步获取数据后的赋值。
  2. 使用setInterval或者setTimeout的。
  3. 添加监听事件addEventListener的。

处理

对于异步获取数据后的赋值,主要有两种解决思路。

一种是,直接通过请求工具提供的强制中断请求方法。

一种是,让请求继续,但不进行后面的赋值。

强制中断的话,我归纳一下帮助文档:

axios https://github.com/axios/axios#cancellation

fetch https://developer.mozilla.org/en-US/docs/Web/API/AbortController

umi-request https://github.com/umijs/umi-request#use-cancel-token

例子我直接使用外国网友的一段代码,来自@Igor Quirino at Dev.to

useEffect(() => {
  const source = axios.CancelToken.source();

  const fetchData = async () => {
    try {
      const response = await Axios.get("/companies", {
        cancelToken: source.token
      });
      // ...
    } catch (error) {
      if (Axios.isCancel(error)) {
        //cancelled
      } else {
        throw error;
      }
    }
  };

  fetchData()

  return () => {
    source.cancel();
  };
}, [companies]);

这个意思很好理解了,就是useEffect return一个函数,里面执行这个取消。

另外一种,不赋值的例子,可以参考 https://codesandbox.io/s/jvvkoo8pq3

 

对于使用setInterval或者setTimeout的,就简单一点,直接clearInterval()。

对于添加监听事件addEventListener的,那就是在函数中removeEventListener。

参考

参考资料对我很重要,我按重要度排序,建议参考。

谈谈js中的内存泄漏-逐梦个人博客

https://dev.to/iquirino/react-hook-clean-up-useeffect-24e7

https://dev.to/otamnitram/react-useeffect-cleanup-how-and-when-to-use-it-2hbm

https://www.rockyourcode.com/avoid-memory-leak-with-react-setstate-on-an-unmounted-component/

https://medium.com/@selvaganesh93/how-to-clean-up-subscriptions-in-react-components-using-abortcontroller-72335f19b6f7

https://codesandbox.io/s/jvvkoo8pq3 ReactHook官方示例

点赞