为什么状态没有按预期更新?

Why does state not update as expected?

我目前正在构建一个 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)
}

任何帮助弄清楚如何让这个函数达到 return 更新状态值的人都会很棒!

setState 是异步的,所以状态不会立即更新。您可以将回调作为第二个参数传递给 setState,它只会在状态更新时调用:

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

setState(React 文档):

setState(updater[, callback]) OR setState(stateChange[, callback])

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

注意:我建议使用 React Dev Tools 观察状态,而不是记录它。


UPDATE:这个答案最初错误地指出 setState 返回了一个 promise 并建议您可以链接 .then() 将被调用一次的状态已更新。从那以后,我在 @Sushanth's .

的启发下更正了答案

状态变化 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);

状态变化 asynchronous。所以使用一个函数代替 setState 函数的第二个参数,你可以调用回调函数 console 或做其他事情。

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