本文主要介绍对useEffect中清理副作用的思考,并提供部分处理案例。
起因
我在读react hook文档的时候,读到一个章节叫做“需要清除的 effect”。其中提到“……还有一些副作用是需要清除的。例如订阅外部数据源。这种情况下,清除工作是非常重要的,可以防止引起内存泄露!……”。
订阅外部数据源我貌似明白,但是从来没听过需要清理什么东西,所以我对订阅外部数据源产生了疑惑。后来在微信群中询问,没有人回复。只好自己查了。
理解
我最终的理解是,在做异步操作的时候,被打断了。一般打断不要紧,关键这个打断影响了后面语句的执行。这时候,需要做一个突然被打断的考虑。也就是文档中提到的防止引起内存泄漏。
典型场景可能有三个:
- 异步获取数据后的赋值。
- 使用setInterval或者setTimeout的。
- 添加监听事件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。
参考
参考资料对我很重要,我按重要度排序,建议参考。
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://codesandbox.io/s/jvvkoo8pq3 ReactHook官方示例