Реакция setState не обновляется немедленно
Я работаю над приложением todo. Это очень упрощенная версия нарушившего код. У меня есть флажок:
<p><input type="checkbox" name="area" checked={this.state.Pencil} onChange={this.checkPencil}/> Writing Item </p>
Здесь функция, которая вызывает флажок:
checkPencil(){
this.setState({
pencil:!this.state.pencil,
});
this.props.updateItem(this.state);
}
updateItem - это функция, отображаемая для отправки в reducex
function mapDispatchToProps(dispatch){
return bindActionCreators({ updateItem}, dispatch);
}
Моя проблема в том, что когда я вызываю действие updateItem и console.log, это всегда на 1 шаг вперед. Если флажок снят и не верен, я все равно получаю состояние true, которое передается функции updateItem. Мне нужно вызвать другую функцию, чтобы заставить государство обновляться?
Ответы
Ответ 1
Вы должны вызывать свою вторую функцию как обратный вызов для setState, поскольку setState происходит асинхронно. Что-то вроде:
this.setState({pencil:!this.state.pencil}, myFunction)
Однако в вашем случае, так как вы хотите, чтобы эта функция вызывалась с параметром, вам нужно будет сделать немного более творческим и, возможно, создать свою собственную функцию, которая вызывает функцию в реквизитах:
myFunction = () => {
this.props.updateItem(this.state)
}
Объедините их вместе, и он должен работать.
Ответ 2
Вызов setState()
в React является асинхронным по различным причинам (в основном, производительности). Под обложками React будет выполнять несколько вызовов до setState()
в одну мутацию состояния, а затем повторно отображать компонент за один раз, а не повторять рендеринг для каждого изменения состояния.
К счастью, решение довольно просто - setState
принимает параметр обратного вызова:
checkPencil(){
this.setState({
pencil:!this.state.pencil,
}, function () {
this.props.updateItem(this.state);
}.bind(this));
}
Ответ 3
Когда вы обновляете свое состояние с использованием свойства текущего состояния, документация React советует вам использовать версию вызова функции setState
вместо объекта.
So setState((state, props) => {...})
вместо setState(object)
.
Причина в том, что setState
- это скорее запрос на изменение состояния, а не немедленное изменение. Реагировать на пакеты setState
требует повышения производительности.
Значение свойства состояния, которое вы проверяете, может быть нестабильным.
Это потенциальная ошибка, о которой нужно знать.
Подробнее см. здесь: https://facebook.github.io/react/docs/react-component.html#setstate
Чтобы ответить на ваш вопрос, я бы сделал это.
checkPencil(){
this.setState((prevState) => {
return {
pencil: !prevState.pencil
};
}, () => {
this.props.updateItem(this.state)
});
}
Ответ 4
Это потому, что это происходит асинхронно, поэтому средства в это время еще не могут обновиться...
В соответствии с документацией React v.16 вам нужно использовать вторую форму setState()
, которая принимает функцию, а не объект:
Обновления состояния могут быть асинхронными
React может выставлять несколько вызовов setState() в одно обновление для производительность.
Поскольку this.props и this.state могут обновляться асинхронно, вы не должны полагаться на свои значения для вычисления следующего состояния.
Например, этот код может не обновить счетчик:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
Чтобы исправить это, используйте вторую форму setState(), которая принимает функцию а не объект. Эта функция получит предыдущее состояние как первый аргумент, так и реквизит в момент применения обновления как второй аргумент:
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
Ответ 5
У Бена есть большой ответ на вопрос о том, как решить ближайшую проблему, однако я бы также посоветовал избежать дублирования состояния
Если состояние находится в сокращении, ваш флажок должен считывать собственное состояние из поддержки или хранилища, а не отслеживать состояние проверки как в своем собственном компоненте, так и в глобальном хранилище
Сделайте что-то вроде этого:
<p>
<input
type="checkbox"
name="area" checked={this.props.isChecked}
onChange={this.props.onChange}
/>
Writing Item
</p>
Общее правило заключается в том, что если вы обнаружите, что состояние необходимо в нескольких местах, поднимите его на общий родительский элемент (не всегда сокращать), чтобы поддерживать только один источник истины
Ответ 6
попробуйте это
this.setState({inputvalue: e.target.value}, function () {
console.log(this.state.inputvalue);
this.showInputError(inputs[0].name);
});
showInputError функция для проверки при использовании любых форм
Ответ 7
Я использовал предложения rossipedia и Ben Hare и сделал следующее:
checkPencil(){
this.setState({
pencil:!this.state.pencil,
}, this.updatingItem);
}
updatingItem(){
this.props.updateItem(this.state)
}