【问题标题】:ReactJS: Error while solving memory leak using makeCancellable methodReactJS:使用 makeCancellable 方法解决内存泄漏时出错
【发布时间】:2019-07-03 22:46:53
【问题描述】:

我在我的 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() 得到相同的内存泄漏错误和另一个错误

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方法解决内存泄漏错误的方法。

我将不胜感激。

【问题讨论】:

    标签: reactjs


    【解决方案1】:

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

    makeCancelable 被滥用,它不会导致它包装的整个 Promise 链不被执行,因为 Promise 不可取消。

    应该是:

    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)))
    

    【讨论】:

    • 感谢您的回答...但是使用 Axios 取消的第二个解决方案,我怎样才能通过 { cancel: this.cancelRequest.token } 以及标题 axiosClient.get('/todoList', {headers: {'授权':})
    • 通过传递 cancelheader 属性,就像 JS 中的其他任何地方一样。这是配置对象,github.com/axios/axios#request-config
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    相关资源
    最近更新 更多