无法在尚未安装的组件上调用 setState

IT技术 javascript reactjs mobx mobx-react
2021-03-31 10:00:15

这是我第一次面对这个警告信息。

无法在尚未安装的组件上调用 setState。

如下:

这是一个空操作,但它可能表明您的应用程序中存在错误。相反,在 MyComponent 组件中this.state直接分配或定义state = {};具有所需状态类属性。

尚未安装”部分实际上几乎没有任何意义,因为触发该问题的唯一方法是通过单击需要安装的组件中的按钮来调用函数以查看该按钮。该组件也不会在任何给定时间卸载。

这个虚拟组件重现了我的应用程序中的错误:

import PropTypes from 'prop-types'
import React from 'react'

export default class MyComponent extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      initial: 'state'
    }
    this.clickMe = this.clickMe.bind(this)
  }

  clickMe () {
    this.setState({
      some: 'new state'
    })
  }

  render () {
    return (
      <div>
        <button onClick={this.clickMe}>click</button>
      </div>
    )
  }
}

我在用:

"react": "16.3.2",
"react-dom": "16.3.2",
"mobx": "4.2.0",
"mobx-react": "5.1.2",

我是否错过了最新的 React/mobx 版本中的某些内容?(注意该组件不使用任何与 mobx 相关的东西,但它的父级是一个 mobx-react 观察者)

编辑:

肯定有与组件实例相关的东西,进一步调查表明,在某些情况下,在渲染函数内创建处理程序会使此警告消失,但并非在所有情况下。

class MyComponent extends React.component {
  constructor (props) {
    // ...
    this.clickMeBound = this.clickMe.bind(this)
  }

  clickMe () {
    ...
  }

  render () {
    // works
    <button onClick={() => {this.clickMe()}}>click arrow in render</button>

    // warning: Can't call setState on a component that is not yet mounted.
    <button onClick={this.clickMeBound}>click bound</button>
  }
}

编辑2:

我已经从我的 Webpack 配置中的条目中删除了“react-hot-loader/patch”,并且一些像这样的奇怪问题已经消失了。我没有把它作为答案,因为错误消息本身仍然很奇怪,这会导致控制台中出现警告。不过一切正常。

6个回答

您收到的这个警告是因为您在构造函数中设置了对clickMe 方法的引用,然后使用setState()

constructor (props) {
    super(props)
    this.state = {
       initial: 'state',
       some: ''          
    }
   this.clickMe = this.clickMe.bind(this);   <--- This method
  }

 clickMe () {
   this.setState({
     some: 'new state'    <-- the setState reference that is causing the issue
   })
  }

尝试从构造函数中删除this.clickMe = this.clickMe.bind(this)并在生命周期方法中执行此操作,例如componentWillMount() 或 ComponentDidMount()对于 react 16 及更高版本,您可以使用带有“SAFE_”前缀componentWillMount 方法[SAFE_componentWillMount]

 componentWillMount() {
      this.clickMe = this.clickMe.bind(this);
 }

clickMe () {
   this.setState({
     some: 'new state'    
   })
  }

只需将以下行添加到您的代码中

export default class MyComponent extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
       initial: 'state',
       some: ''          // <-------  THIS LINE
    }
   this.clickMe = this.clickMe.bind(this)
  }

 clickMe () {
   this.setState({
     some: 'new state'
   })
  }

 render () {
   return (
     <div>
       <button onClick={this.clickMe}>click</button>
     </div>
   );
  }
}
因为直到 clickMe() 方法才定义状态“some”
2021-05-30 10:00:15
你能解释一下,他为什么要这样做?这条线对我来说似乎有点随机?
2021-06-13 10:00:15

您只需要使用该componentDidMount()方法。正如 React 文档在组件生命周期中所说,如果您需要从远程端点加载数据,这是实例化网络请求的好地方,您可以setState()立即调用componentDidMount().

像这样:

componentDidMount(){
  this.clickMe = this.clickMe.bind(this);
}
clickMe () {
  this.setState({
    some: 'new state'
  })
}

正如@Amida 所提到的,热加载器似乎是问题所在。谁在使用

app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
    HotModuleReplacement = true,
    ReactHotModuleReplacement = true
});

在 Startup.cs 中,删除它,问题就会消失。我不知道为什么,但这是我目前的解决方法。

编辑:

将“react-hot-loader”和“webpack-hot-middleware”更新到最新版本修复了该问题

您不应在构造函数中使用 setState,因为该组件尚未安装。在这种情况下,clickMe() 方法调用 setState()。
相反,直接初始化状态。喜欢,

constructor(props) {
    super(props);
    // Don't call this.setState() here!
    this.state = { counter: 0 };
    this.handleClick = this.handleClick.bind(this);
}

例如,如果来自https://reactjs.org/docs/react-component.html#constructor

使用 setState() 以便我们可以通过重新渲染来反映状态变化。由于组件尚未呈现,我们可以直接更改状态,更改将反映在 render() 方法的调用上。

我的示例代码已经是这样了。无论如何,在某些情况下,问题是由 react-hot-loader 引起的,人们正在转向 react-refresh。
2021-06-08 10:00:15