【问题标题】:React - Memory Leak, issues with ComponentWillUnmount / AxiosReact - 内存泄漏,ComponentWillUnmount / Axios 的问题
【发布时间】:2020-03-01 19:00:02
【问题描述】:

我正在执行一个使用 componentDidMount 启动的 API 调用,但是当用户加载一个新组件时,会有一个潜在内存泄漏的通知,请参阅下面的消息。我研究了不同的解决方案,但还没有发现任何可行的方法,我想知道是否可以使用 componentWillUnmount 在此特定组件中修复此问题,或者是否可以在 axios 调用本身中更好地处理。

无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要修复,请在 componentWillUnmount 方法中取消所有订阅和异步任务。

componentDidMount() {
    this.loadBackground();
    this.getUpdatedWeather();
    this.getNewMartianPhotos();
  }

  checkMartianPhotos = () => {
    if (this.state.martianMotion) {
      console.log('still shooting');
      this.getNewMartianPhotos();
    } else {
      return console.log('done now');
    }
  };

  getNewMartianPhotos = () => {
    let loadedImage = '';
    let loadedInfo = '';
    let loadedMeta = '';
    let totalImage;

    API.getMarsPhotos().then(data => {
      // console.log(data.data);
      // console.log(
      //   data.data.collection.items[this.state.martianCount].data[0].photographer
      // );
      // console.log(
      //   data.data.collection.items[this.state.martianCount].data[0].description
      // );
      // console.log(
      //   data.data.collection.items[this.state.martianCount].links[0].href
      // );

      totalImage = data.data.collection.items.length;
      loadedImage =
        data.data.collection.items[this.state.martianCount].links[0].href;
      loadedInfo =
        data.data.collection.items[this.state.martianCount].data[0].description;
      loadedMeta =
        data.data.collection.items[this.state.martianCount].data[0]
          .photographer;

      this.setState({
        martianImage: loadedImage,
        martianDescription: loadedInfo,
        martianMeta: loadedMeta,
        martianCount: this.state.martianCount + 1
      });

      if (this.state.martianCount < totalImage) {
        console.log(
          `shooting off, image count now ${this.state.martianCount} against ${totalImage}`
        );
        setTimeout(this.checkMartianPhotos, 10000);
      }
    });
  };

  componentWillUnmount() {
    clearTimeout(this.checkMartianPhotos);
  }


-------------------------------------

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

  getMarsPhotos: () =>
    axios
      .get('https://images-api.nasa.gov/search?q=martian', {
        cancelToken: source.token
      })
      .catch(function(thrown) {
        if (axios.isCancel(thrown)) {
          console.log('request canceled', thrown.message);
        } else {
          console.log('there is an error that needs to be handled');
        }
      })

【问题讨论】:

  • 尝试取消componentWillUnmount中的请求。
  • 也许取消请求是不够的,你需要取消承诺见reactjs.org/blog/2015/12/16/ismounted-antipattern.html。如果你使用 redux,你可以使用 redux-saga 来取消。但首先要了解为什么会发生这种情况,也许这是不好的实现。分享代码框以便更好地检查。

标签: reactjs memory-leaks axios setstate


【解决方案1】:

正如错误提示,您的组件在卸载后调用 setState。这是因为您错误地清除了超时。您应该执行以下操作以正确清除卸载超时。

this.id = setTimeout(this.checkMartianPhotos, 10000);

然后用清除

clearTimeout(this.id)

在组件WillUnmount中

另外,尝试将异步逻辑(api 调用)移出组件。

请参阅this,了解如何在未安装组件上调用 API 后停止设置状态。

【讨论】:

  • 好吧,isMounted 的反应文档状态是反模式,请参阅reactjs.org/blog/2015/12/16/ismounted-antipattern.html
  • @gadi tzkhori 真的!这就是为什么我要求 OP 将异步逻辑移出组件。感谢您的分享。
  • 您好 Hassaan,我想让您知道这确实解决了我的问题,非常感谢您的帮助。我的 API 调用在一个单独的文件中,但我想包含信息以防它提供任何见解,我将通过您留下的链接进一步阅读该主题,再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-28
相关资源
最近更新 更多