前阵子在开发过程中遇到了React-组件卸载时内存泄漏的问题,在这里记录一下:
问题描述
使用react开发的项目在切换页面的时候,报了下面这个错:
Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method”
大致的意思就是说,在组件已被卸载的情况下不能再去设置组件的state,这可能会导致内存泄漏。
这个问题是在什么场景出现的呢?一般是出现在异步请求上。
想象这样一个场景:你在组件中发出了一个异步请求,回调中设置了组件的state。当这个异步请求还在路上的时候,你的组件已经被卸载掉了,等待异步请求返回后他还是会去设置这个已被卸载的组件的state,这样可能就会导致一些不可预料的错误。
解决思路
最简单的想法当然是在编码的时候注意,尽量避免这样的情况发生。但是有时候这种情况是不可避免的,所以我们应该从根源上解决这个问题。错误发生的原因其实就是在组件卸载之后去设置state了,所以我们只要在组件已被卸载后不设置state就可以了。这里可以通过装饰器来实现。代码如下:
function inject_unmount(target: any) { // 改装componentWillUnmount let next = target.prototype.componentWillUnmount; target.prototype.componentWillUnmount = function() { if (next) next.call(this, ...arguments); this.unmount = true; }; // 改装setState let setState = target.prototype.setState; target.prototype.setState = function() { if (this.unmount) return; setState.call(this, ...arguments); }; }我们先是对组件的componentWillUnmount做了改装,当组件将要卸载的时候设置一个unmount变量,主要是用来后面setState的时候查看。
然后我们再对setState做改装,每次setState的时候就去判断一下是否有unmount这个变量。如果有的话就说明组件即将被卸载或者已经被卸载,这个时候我们就不去setState了,直接返回。
使用
使用方法如下:
@inject_unmount class Example extends React.Component{ ... }