Реакция 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)
}