Ответ 1
Ваш пример не воспроизводит ошибку. (Slight Modifications) codesandbox
это первый раз, когда я сталкиваюсь с этим предупреждением.
Невозможно вызвать setState для компонента, который еще не смонтирован.
Следит:
Это не работает, но это может указывать на ошибку в вашем приложении. Вместо этого присвойте
this.state
напрямую или определитеstate = {};
свойство класса с желаемым состоянием в компоненте MyComponent.
" Еще не смонтированная " часть фактически не имеет особого смысла, поскольку единственный способ вызвать проблему - вызвать функцию, нажав кнопку в компоненте, который необходимо смонтировать, чтобы увидеть кнопку. Компонент не демонтируется в любой момент времени.
Этот фиктивный компонент воспроизводит ошибку в моем приложении:
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).
Редактировать:
Должно быть что-то, связанное с экземпляром компонента, дальнейшее исследование показало, что в некоторых случаях создание обработчика внутри функции рендеринга делает это предупреждение исчезающим, но не во всех случаях.
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:
Я удалил "response-hot-loader/patch" из своих записей в конфигурации Webpack, и некоторые странные проблемы, подобные этой, исчезли. Я не помещаю это как ответ, потому что само сообщение об ошибке все еще странно, и это вызывает предупреждение в консоли. Все работает хорошо, хотя.
Ваш пример не воспроизводит ошибку. (Slight Modifications) codesandbox
Просто добавьте эту строку кода в код
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 удалите его, и проблема исчезнет. Я не знаю почему, но это мой текущий обходной путь.
РЕДАКТИРОВАТЬ:
Обновление "response-hot-loader" и "webpack-hot-middleware" до последних версий устранило проблему
Если эта ошибка возникает в одном из ваших тестов, вам может потребоваться render
компонент для элемента, прежде чем получить к нему доступ (то есть простого выполнения let app = new App;
недостаточно). При рендеринге будет эффективно монтироваться компонент и его дочерние элементы, как описано в этом другом ответе, и тогда вы сможете использовать объект результата для выполнения операций, не вызывая ошибку 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 ( ... ) }
}