Javascript React setState 只能更新一个挂载或挂载的组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35345338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:36:55  来源:igfitidea点击:

React setState can only update a mounted or mounting component

javascriptreactjs

提问by erichardson30

I am getting the following warning

我收到以下警告

"Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the ContactPage component."

“警告:setState(...):只能更新已安装或正在安装的组件。这通常意味着您在未安装的组件上调用了 setState()。这是一个空操作。请检查 ContactPage 组件的代码。”

When I initially go to the contact page the firs time it is fine. Then if I navigate off the page and go back the warning is thrown.

当我第一次进入联系页面时,它很好。然后,如果我离开页面并返回,则会抛出警告。

Contact page component :

联系页面组件:

import React, { Component, PropTypes } from 'react';
import AppStore from '../../stores/AppStore';
import AppActions from '../../actions/AppActions';
import DataContent from './DataContent';

const title = 'Contact Us';


class ContactPage extends Component {

    constructor(props) {
        super(props);
        this.state = AppStore.getState();
        AppActions.getData();
    }

  static contextTypes = {
    onSetTitle: PropTypes.func.isRequired,
  };

  componentWillMount() {
    this.context.onSetTitle(title);
    AppStore.listen(this.onChange.bind(this));
}

componentWillUnmount() {
    AppStore.unlisten(this.onChange.bind(this));
}

onChange(state) {
    this.setState(state);
}

renderData() {
    return this.state.data.map((data) => {
        return (
            <DataContent key={data.id} data={data} />
        )
    })
}

  render() {
    return (
      <div className={s.root}>
        <div className={s.container}>
          <h1>{title}</h1>
          <div>
              { this.renderData() }
          </div>
        </div>
      </div>
    );
}

}

export default ContactPage;

When I put debuggers in, on load of contact page it hits componentWillMount(). When I leave the contact page it hits componentWillUnmount(). When I navigate back to the page it hits componentWillMount() again and then throws the error when it hits the onChange(state) function.

当我放入调试器时,在加载联系页面时它会点击 componentWillMount()。当我离开联系页面时,它会点击 componentWillUnmount()。当我导航回页面时,它再次点击 componentWillMount() ,然后在点击 onChange(state) 函数时抛出错误。

回答by Felix Kling

The issue is that the listener of the previous component instance is still registered. And because the previous instance isn't mounted anymore, you get that error.

问题是前一个组件实例的侦听器仍然注册。并且由于之前的实例不再安装,您会收到该错误。

.bindalways returns a newfunction. So if you do

.bind总是返回一个函数。所以如果你这样做

AppStore.unlisten(this.onChange.bind(this));

then you are trying to remove a listener that doesn't exist (which fails of course). It does notremove the listener you registered with AppStore.listen(this.onChange.bind(this))

那么您正在尝试删除不存在的侦听器(当然失败了)。它并不会删除您注册的监听器AppStore.listen(this.onChange.bind(this))



To solve this, you should bind the handler oncein the constructor:

要解决这个问题,您应该在构造函数中绑定一次处理程序:

this.onChange = this.onChange.bind(this);

and then use AppStore.listen(this.onChange)and AppStore.unlisten(this.onChange).

然后使用AppStore.listen(this.onChange)AppStore.unlisten(this.onChange)

回答by Janaka Pushpakumara

Before the change, state check component is mounted.

在更改之前,状态检查组件已安装。

render() {
   return (
     <div ref="root" className={s.root}>
       // ----
     </div>
   )};

 onChange(state) {
   if(this.refs.root) {
     this.setState(state);
   }
 }

I think this will help to you.

我想这会对你有所帮助。

回答by rEjITh

In your case add a ref to your root div and check the ref value before you call setState.

在您的情况下,向您的根 div 添加一个 ref 并在调用 setState 之前检查 ref 值。

Your onChangemethod should looks like this:

您的onChange方法应如下所示:

onChange(state) {
    this.refs.yourRef ? this.setState(state) : null;    
}

回答by Yuri Nalin

I was struggling with this issue as well for quite a while.

我也在这个问题上挣扎了很长一段时间。

What solved for me was to do as @Felix Kling proposed but also make sure my callback function was declared within the component's class, otherwise you're not able to use the thisprefix, wich was apparently what did the trick for me.

为我解决的是按照@Felix Kling 的建议进行操作,但还要确保在组件的类中声明了我的回调函数,否则您将无法使用this前缀,这显然对我有用。

Here is an example of what I mean:

这是我的意思的一个例子:

Legal, but doesn't work

合法,但不起作用

function onChange() { 
  this.setState({ MyState: newState })
}

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    onChange = onChange.bind(this);
  }

  componentDidMount() {
    window.addEventListener('resize', onChange);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', onChange);
  }

  render() { ... }
}

Works

作品

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.onChange = this.onChange.bind(this);
  }

  onChange() { 
    this.setState({ MyState: newState })
  }

  componentDidMount() {
    window.addEventListener('resize', this.onChange);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.onChange);
  }

  render() { ... }
}

Hope it helps anyone else facing this problem. :)

希望它可以帮助其他任何人面临这个问题。:)