Почему состояние не обновляется, как ожидалось? - PullRequest
2 голосов
/ 21 марта 2019

Я сейчас создаю игру TicTacToe и хотел бы сохранить моего текущего игрока в состоянии currentPlayer. После перемещения одного игрока я обновляю currentPlayer для другого игрока. Однако, когда я пытаюсь записать новое состояние в консоль, оно не выдает значение обновленного состояния.

Вот мой код:

state = {
    currentPlayer: 'X',
}

// This function is triggered by an onClick attribute.
// It first finds the html element and renders the currentPlayer value from state.
// It then switchs the value of currentPlayer from X to O and calls setState to update the state.
// Why does the console.log not show the updated state value?

userDidMove = () => {
    document.getElementById('cell').innerHTML = this.state.currentPlayer
    let nextPlayer = this.state.currentPlayer === 'X' ? 'O' : 'X'
    this.setState({ 
        currentPlayer: nextPlayer,
    })
    console.log ('userDidMove changed state with ',this.state.currentPlayer)
}

Было бы здорово помочь выяснить, как заставить эту функцию возвращать обновленное значение состояния!

Ответы [ 3 ]

3 голосов
/ 21 марта 2019

Изменения состояния asynchronous.Когда ваше новое состояние зависит от предыдущего состояния, используйте вместо него функцию обновления состояния.

Когда изменения состояния будут зафиксированы, вы можете использовать обратный вызов, который будет иметь обновленное состояние.

this.setState((previousState) => {
  const nextPlayer = previousState.currentPlayer === 'X' ? 'O' : 'X';

  return {
    currentPlayer: nextPlayer
  }
}, () => {
  // your updated state related code here

  console.log('userDidMove changed state with ', this.state.currentPlayer)
});

this.setState(updatedFunc, callback);
1 голос
/ 21 марта 2019

setState является асинхронным, поэтому состояние не обновляется немедленно. Вы можете передать обратный вызов в качестве второго аргумента setState, который будет вызываться только при обновлении состояния:

this.setState(
  { currentPlayer: nextPlayer },
  () => console.log(`userDidMove changed state with ${this.state.currentPlayer}`)
);

setState (React Docs):

setState(updater[, callback]) ИЛИ setState(stateChange[, callback])

Думайте о setState () как о запросе, а не как о немедленной команде обновить компонент. Для лучшего восприятия производительности React может задержать его, а затем обновить несколько компонентов за один проход. реагировать не гарантирует, что изменения состояния будут применены немедленно.

setState () не всегда сразу обновляет компонент. Это может Пакет или отложить обновление до позже. Это делает чтение this.state сразу после вызова setState () потенциальная ловушка. Вместо этого используйте componentDidUpdate или обратный вызов setState (setState (Updater, callback)), любой из которых гарантированно сработает после обновления был применен. Если вам нужно установить состояние на основе предыдущего состояние, прочитайте об аргументе обновления ниже.

ПРИМЕЧАНИЕ. Я предлагаю наблюдать за состоянием, используя React Dev Tools вместо его регистрации.


ОБНОВЛЕНИЕ : В этом ответе изначально неверно указывалось, что setState вернул обещание и предложил, чтобы вы могли связать .then(), который будет вызываться после обновления состояния. С тех пор я исправил ответ, вдохновленный @ Sushanth 's answer .

0 голосов
/ 21 марта 2019

Изменения состояния asynchronous.поэтому вместо этого используйте функцию и второй параметр функции setState, вы можете вызвать функцию обратного вызова для console или сделать что-то еще.

this.setState(() => ({currentPlayer: nextPlayer}), () => {
  console.log('state', this.state.currentPlayer);
})
...