为什么州不按预期更新?

问题描述 投票:2回答:3

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

任何帮助弄清楚如何让这个函数返回更新的状态值将是伟大的!

javascript reactjs tic-tac-toe setstate
3个回答
3
投票

状态变化是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
投票

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可能会延迟它,然后在一次通过中更新几个组件。 React不保证立即应用状态更改。

setState()并不总是立即更新组件。它可以批量推迟更新或推迟更新。这使得在调用setState()之后立即读取this.state是一个潜在的陷阱。相反,使用componentDidUpdate或setState回调(setState(更新程序,回调)),其中任何一个都保证在应用更新后触发。如果需要根据以前的状态设置状态,请阅读下面的updater参数。

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


更新:这个答案最初说错了,setState返回了一个承诺,并建议你可以链接.then(),一旦状态更新就会被调用。我已经纠正了答案,灵感来自@Sushanthanswer


0
投票

状态变化是asynchronous。所以使用函数而不是setState函数的第二个参数你可以调用console的回调函数或其他事情来做。

this.setState(() => ({currentPlayer: nextPlayer}), () => {
  console.log('state', this.state.currentPlayer);
})
© www.soinside.com 2019 - 2024. All rights reserved.