Reputation: 43
I'm trying to learn hooks in React.js by rewriting a "Rock Paper Scissor" game. I can't get the winner evaluated at the same time when I press the choosen button. This is my code (it's a shorter code where I compare just the player pressing the paper button):
function App() {
const weapons = ["paper","scissors","rock"];
const [choice, setChoice] = useState({
playerOne: "",
playerTwo: "",
winner: ""
})
const chooseWeapon=(weapon)=>{
setChoice({
playerOne: weapon,
playerTwo: weapons[Math.floor(Math.random() * 3)],
winner: getWinner(choice.playerOne,choice.playerTwo)
})
}
const getWinner = (player1,player2)=>{
if(player1==="paper"){
if(player2==="scissors"){
return("player two won")
} else if(player2==="rock"){
return("player one won!!!!!")
}
}
}
return (
<div className="App">
<h1>Rock scissors lizard</h1>
<h2>player one:{choice.playerOne}</h2>
<h2>player two:{choice.playerTwo}</h2>
<h1>{choice.winner}</h1>
<button onClick={()=>chooseWeapon("paper")}>paper</button>
<button onClick={()=>chooseWeapon("scissors")}>scissors</button>
<button onClick={()=>chooseWeapon("rock")}>rock</button>
</div>
);
}
export default App;
Basically when I click on the "paper" button, I get rendered on the screen choice of each player, but I will get the winner status only after I press it again. The winner render is always one step behind. How can I fix this?
Thank you guys!
Upvotes: 2
Views: 149
Reputation: 282140
State updates do not happen immediately but in the next render cycle, so when you expect that the winner variable will be evaluted based on player 1 and player 2 choice, its actually based on previous value. To solve this, you need to calculate winner first and then set it in state
function App() {
const weapons = ["paper","scissors","rock"];
const [choice, setChoice] = useState({
playerOne: "",
playerTwo: "",
winner: ""
})
const chooseWeapon=(weapon)=>{
const choiceP1 = weapon;
const choiceP2 = weapons[Math.floor(Math.random() * 3)];
const winner = getWinner(choiceP1, choiceP2)
setChoice({
playerOne: choiceP1,
playerTwo: choiceP2,
winner,
})
}
const getWinner = (player1,player2)=>{
if(player1==="paper"){
if(player2==="scissors"){
return("player two won")
} else if(player2==="rock"){
return("player one won!!!!!")
}
}
}
return (
<div className="App">
<h1>Rock scissors lizard</h1>
<h2>player one:{choice.playerOne}</h2>
<h2>player two:{choice.playerTwo}</h2>
<h1>{choice.winner}</h1>
<button onClick={()=>chooseWeapon("paper")}>paper</button>
<button onClick={()=>chooseWeapon("scissors")}>scissors</button>
<button onClick={()=>chooseWeapon("rock")}>rock</button>
</div>
);
}
export default App;
Upvotes: 4
Reputation: 19234
In the function where you are passing in arguments to determine the winner of the game:
setChoice({
playerOne: weapon,
playerTwo: weapons[Math.floor(Math.random() * 3)],
winner: getWinner(choice.playerOne,choice.playerTwo)
})
here, choice.playerOne
and choice.player2
that you are referring to aren't set yet. What you would need to do is to pass in the current choices for playerOne and playerTwo.
const playerOne = weapon;
const playerTwo = weapons[Math.floor(Math.random() * 3)];
setChoice({
playerOne,
playerTwo,
winner: getWinner(playerOne, playerTwo),
})
Upvotes: 3