美文网首页
避免已卸载的组件继续调用setState()

避免已卸载的组件继续调用setState()

作者: 陈鑫呀 | 来源:发表于2019-02-27 11:07 被阅读0次

本文转载自我的个人博客

这是一篇译文,原文在这里。有兴趣的同学可以直接阅读原文,写的很好。图省事的同学可以直接看我的精简的译文。

相信很多react初学者都遇到过以下两个警告(warnings)

  • Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.

  • Warning: Can’t call setState (or forceUpdate) 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.

一般来说警告并不会让你的程序崩溃,但是它会降低程序的性能,比如我们上面提到的这两个警告就是这样。下面让我们来讨论一下这两个警告到底讲的是什么吧。

当一个已经被卸载(unmounted)的组件调用setState()方法时,你就会遇到以上两个警告。一般来说,有两种情况会导致组件的卸载:

  1. 通过条件渲染的组件,其渲染条件从达到变为没有达到,导致已渲染的组件的卸载
  2. 通过路由手段路由到别的组件,导致原组件被卸载

当组件被卸载后,被卸载的组件内的某些异步逻辑可能在组件被卸载后调用了setState()企图更新组件内的state,通常有三种场景可能会发生这种情况:

  1. 你对某个API提交了一个异步请求,组件在收到响应前就被卸载了,收到响应之后调用了setState()企图更新state,但这个时候组件早就被卸载了。
  2. 你为组件添加了监听事件,但是没有在componentWillUnmount()里移除这个监听事件,当组件移除以后监听的事件被触发。
  3. 你在类似于setInterval()的函数里调用了setState(),但是没有在componentWillUnmount()里移除这些函数。

那么在遇到以上两个警告时我们怎么样才能解决他们呢?

避免 intervals/listeners 在已卸载的组件中调用 setState()

对于上面提到的三种情况中的后两种情况,我们只需要在componentWillUnmount()生命周期钩子里将intervals/listeners移除就可以了。具体操作可以参考这个例子

避免异步请求在已卸载的组件中调用 setState()

为了避免异步请求在已卸载的组件中调用setState(),我们可以在请求收到响应后添加一个判断条件,判断此时组件有没有被卸载,如果没有卸载再继续执行之后的代码(比如setState())。具体实现如下:

  class News extends Component {
    //添加一个 class field 记录组件有没有被卸载,初始化为false,表示已卸载
    _isMounted = false;

    constructor(props) {
      super(props);

      this.state = {
        news: [],
      };
    }

    componentDidMount() {
      //组件在被挂载后将_isMounted的值更新为true,表示已挂载
      this._isMounted = true;

      axios
        .get('https://hn.algolia.com/api/v1/search?query=react')
        .then(result => {
          //通过_isMounted判断组件有没有被卸载
          if (this._isMounted) {
            this.setState({
              news: result.data.hits,
            });
          }
        });
    }

    componentWillUnmount() {
      //在组件被卸载时将_isMounted更新为false,表示组件已卸载
      this._isMounted = false;
    }

    render() {
      ...
    }
  }

一个小插曲,关于class field是什么,给大家两个例子,可以先体会下用class field和不用的区别,以后有时间,我再写一篇专门关于class field的文章。

不用class field:

  class IncreasingCounter {
    constructor() {
      this._count = 0;
    }
    get value() {
      console.log('Getting the current value!');
      return this._count;
    }
    increment() {
      this._count++;
    }
  }

class field:

  class IncreasingCounter {
    _count = 0;
    get value() {
      console.log('Getting the current value!');
      return this._count;
    }
    increment() {
      this._count++;
    }
  }

相关文章

  • 避免已卸载的组件继续调用setState()

    本文转载自我的个人博客。 这是一篇译文,原文在这里。有兴趣的同学可以直接阅读原文,写的很好。图省事的同学可以直接看...

  • Warning: Can't perform a React s

    解释: 这是由于在组件卸载后,组件中仍有 function 能调用 setState ,搜索 setState 就...

  • 2018-09-03 Warning: setState(...

    出现的原因是组件卸载之后调用了setState({}),网络请求耗时时间长,直接返回了某个页面。 异步请求返回结果...

  • React setState

    当组件的 setState 函数被调用之后,会发生什么 ? 在代码中调用setState函数之后,React 会将...

  • react的更新机制

    每次setState都会调用组件的render函数?setState后会进入到shouldComponentUpd...

  • 从 setState promise 化的探讨 体会 React

    从 setState 那个众所周知的小秘密说起... 在 React 组件中,调用 this.setState()...

  • React:虚拟DOM Diff算法

    父组件每次render方法被调用,或者组件自己每次调用setState方法,都会触发组件的render方法(前提是...

  • Props和State的区别

    setState还可以接受第二个参数,它是一个函数,会在setState调用完成并且组件开始重新渲染时被调用,可以...

  • React

    1. 当你调用 setState 的时候,发生了什么事? 将传递给 setState 的对象合并到组件的当前状态,...

  • How Does setState know what to d

    how Does setState know What to do? - Dan 当你在组件中调用 setStat...

网友评论

      本文标题:避免已卸载的组件继续调用setState()

      本文链接:https://www.haomeiwen.com/subject/ujuxuqtx.html