ReactJS:使用makeCancellable方法解决内存泄漏时出错

时间:2019-02-10 05:30:46

标签: reactjs

我在React应用程序中遇到内存泄漏错误。调用API时发生错误。我的应用程序渲染了3次,因为页眉和页脚先获得setState,然后使用setState获得todoList。

下面的控制台错误

警告:无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要解决此问题,请在componentWillUnmount方法中取消所有订阅和异步任务。 index.js:1446

我尝试了_.isMounted方法来解决该问题,并且也可以使用,但是解决方案是deprecated

下面的isMounted方法代码...

_isMounted = false
componentDidMount() {
        this._isMounted = true
        API.getTodoList().then(data => {
          if (this._isMounted) {
            this.setState({ itemList: data.data.itemList });
          }
        })
      }

componentWillUnmount() {
        this._isMounted = false
      }

后来我尝试使用makeCancelable方法修复内存泄漏。但是它并没有解决问题,并且出现了相同的内存泄漏错误,以及来自.catch()的另一个错误 error

API调用:

// makeCancelable fn is defined at start
const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      val => hasCanceled_ ? reject({ isCanceled: true }) : resolve(val),
      error => hasCanceled_ ? reject({ isCanceled: true }) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

componentDidMount() {
    console.log("didMount")
    this.cancelRequest = makeCancelable(
      axiosClient.get('/todoList')
        .then((response) => {
          this.setState({ itemList: response.data.data.itemList })
        })
        .catch(({ isCanceled, ...error }) => console.log('isCanceled', isCanceled))
    )
  }

componentWillUnmount() {
    console.log("componentUnmount")
    this.cancelRequest.cancel();
}

是否有其他方法可以解决内存泄漏错误,而无需使用_.isMounted方法。

我会很感激。

1 个答案:

答案 0 :(得分:0)

该消息警告内存泄漏的可能性。虽然原始代码可能会导致内存泄漏,但这并没有说明一个,具体取决于执行请求的方式

makeCancelable被滥用,因为不能撤销承诺,所以它不会导致包装的整个承诺链无法执行。

应该是:

this.cancelRequest = makeCancelable(
  axiosClient.get('/todoList')
);

cancelRequest.promise
.then(...)
.catch(({ isCanceled, ...error }) => console.log('isCanceled', isCanceled))

因为Axios已经提供了cancellation,所以不需要这样做:

this.cancelRequest = axios.CancelToken.source();

axiosClient.get('/todoList', { cancel: this.cancelRequest.token })
.then(...)
.catch(error => console.log('isCanceled', axios.isCancel(error)))