Giacomo
Giacomo

Reputation: 43

Render a state based on a condition with Hooks (Building a simple rock paper scissors game)

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

Answers (2)

Shubham Khatri
Shubham Khatri

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

Agney
Agney

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

Related Questions