React setState может обновлять только смонтированный или монтажный компонент
Я получаю следующее предупреждение
"Предупреждение: setState (...): может обновлять только смонтированный или монтируемый компонент. Обычно это означает, что вы вызываете setState() на незамонтированном компоненте. Это не работает. Проверьте код компонента ContactPage."
Когда я изначально перехожу на страницу контактов, то в первый раз это нормально. Затем, если я перейду с страницы и вернусь, предупреждение будет выброшено.
Компонент контактной страницы:
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;
Когда я помещаю отладчики, при загрузке контактной страницы он попадает в компонентWillMount(). Когда я покидаю страницу контакта, он попадает в компонентWillUnmount(). Когда я перейду на страницу назад, он снова попадает в состав компонента componentWillMount(), а затем выдает ошибку, когда она попадает в функцию onChange (состояние).
Ответы
Ответ 1
Проблема заключается в том, что слушатель предыдущего экземпляра компонента все еще зарегистрирован. И поскольку предыдущий экземпляр больше не монтируется, вы получаете эту ошибку.
.bind
всегда возвращает новую функцию. Так что если вы делаете
AppStore.unlisten(this.onChange.bind(this));
то вы пытаетесь удалить прослушиватель, который не существует (что, конечно, не выполняется). Он не удаляет слушателя, зарегистрированного в AppStore.listen(this.onChange.bind(this))
Чтобы решить эту проблему, вы должны связать обработчик один раз в конструкторе:
this.onChange = this.onChange.bind(this);
а затем используйте AppStore.listen(this.onChange)
и AppStore.unlisten(this.onChange)
.
Ответ 2
Перед изменением установлен компонент проверки состояния.
render() {
return (
<div ref="root" className={s.root}>
// ----
</div>
)};
onChange(state) {
if(this.refs.root) {
this.setState(state);
}
}
Я думаю, это поможет вам.
Ответ 3
В вашем случае добавьте ref в свой корневой раздел и проверьте значение ref перед вызовом setState.
Ваш метод onChange
должен выглядеть следующим образом:
onChange(state) {
this.refs.yourRef ? this.setState(state) : null;
}