这是我第一次面对这个警告信息。
无法在尚未装入的组件上调用setState。
具体情况如下:
这是一个无操作,但它可能表示您的应用程序中存在错误。相反,直接分配给
this.state
或在MyComponent组件中定义具有所需状态的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观察者)
编辑:
必须有与组件实例相关的东西,进一步的调查表明,在某些情况下,在render函数中创建一个处理程序将使该警告消失,但并非在所有情况下都消失。
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”,这个奇怪的问题已经消失了。我不是把它作为答案,因为错误消息本身仍然很奇怪,这会在控制台中引发警告。一切都很好。
只需将这行代码添加到代码中即可
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>
);
}
}
正如@Amida所提到的,热装载机似乎是个问题。无论谁使用
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ReactHotModuleReplacement = true
});
在Startup.cs中,删除它,问题将消失。我不知道为什么,但这是我目前的解决方法。
编辑:
更新“react-hot-loader”和“webpack-hot-middleware”到最新版本修复了这个问题
如果在您的某个测试中发生此错误,您可能需要在访问元素之前将组件render
(即仅仅执行let app = new App;
是不够的)。渲染将有效mount the component and its children, as explained in this other answer然后你将能够使用结果对象执行操作,而不会触发setState
错误。一个简单的App.test.js
例子:
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div); // <-- App component mounted here
// without JSX: ReactDOM.render(React.createElement(App), div)
ReactDOM.unmountComponentAtNode(div);
});
test('array length decreased after removal', () => {
const div = document.createElement('div');
let app = ReactDOM.render(<App />, div); // <-- App component mounted here
const origArrLen = app.state.arr.length;
app.removeAtIndex(0);
expect(app.state.arr.length).toEqual(origArrLen - 1);
ReactDOM.unmountComponentAtNode(div);
});
App
组件可能具有的位置:
class App extends Component {
state = {
arr: [1,2,3]
};
removeAtIndex = index => {
const { arr } = this.state;
this.setState({ arr: arr.filter((el, i) => i !== index) });
};
// render() { return ( ... ) }
}