Logo

How to build rock, paper and scissors in React, a beginners guide

7 min read

You already know what Rock, Paper and Scissors is. It is a game we have all played. And now that you have started to learn to code, you want to build an app out of it, which is fantastic and is suitable for beginners and an excellent project as a practice.

Today, I will show you how you can build the game using React and explain the process step by step. The final result will look like the below. Let's get started.

Final result

Prerequisites

Before you follow along, you need to know a basic understanding of React, how to create your app, a few hooks like useState() and some knowledge of JavaScript.

For styling, I will provide you with the CSS file, and if you choose to write your own styles, even better! If you want to check out my GitHub repository, click here

Getting started (Setup react app)

The first thing that you want to do is create your react app.

npx create-react-app rock-paper-scissor

Once installed, open your app in your code editor and start clearing out the codes you don’t need, which usually gets installed while creating a react app. You won’t need App.css, remove everything inside your App component in App.js and return a blank div.

function App() {
  return <div>Rock, paper and scissors</div>;
}

export default App

The three components: Scoreboard, Player and Game

You will be creating three different components, Scoreboard, Player and Game. The parent for all these components will be your App.js, from where you will pass props to other components.

The parent App.js

Let's keep App.js as simple as you can. You will only need one hook called useState(), which stores the app's state. You can keep any type of data in useState like string, number, boolean, object or array. You will be using a lot of this hook in your React projects.

function App() {
 const [playersHand, setPlayersHand] = useState('');
 const [score, setScore] = useState(0);

  return (
    <>
      <Scoreboard score={score} />
      <Game score={score} playersHand={playersHand} setScore={setScore} />
      <Player setPlayersHand={setPlayersHand} />
    </>
  );
}

playersHand is the variable, and setPlayerHand is the function that updates the state of playersHand. Same for the score.

You can see <Scoreboard score={score} /> and other components added here. You will be creating those components in the next step. You pass the score to the Scoreboard component, where you display the score. The Game will take score, playershand and setScore, and the Player component will take the setPlayersHand, which sets the player’s hand.

Ensure you don’t forget to import these components once you create them.

Create a Scoreboard component

This is where you will receive our score and render it. You could have done everything in the App component, but this way, you will learn more about passing props to different components.

Create a new folder called components in your src folder, and then create a file called Scoreboard.jsx

const Scoreboard = ({ score }) => {
  return (
    <div className='score-container'>
      <h2>Score</h2>
      <div>{score}</div>
    </div>
  );
};

export default Scoreboard;

Here, = ({ score }) => is the props you passed down from your App.js. That is how you receive the props passed from the parent element. Then create a div, and inside, you are rendering the {score} inside curly brackets {} because it is a JSX component.

The Player component

Now, create another file inside components called Player.jsx. The Player component is for the player. This is where the player chooses its available options, either Rock, Paper or Scissors.

const Player = ({ setPlayersHand }) => {
  const setHand = (e) => {
    setPlayersHand(e.target.id);
  };
  return (
    <div className='container'>
      <button onClick={setHand} id='Rock' className='hand rock'>
        Rock
      </button>
      <button onClick={setHand} id='Paper' className='hand paper'>
        Paper
      </button>
      <button onClick={setHand} id='Scissors' className='hand scissors'>
        Scissors
      </button>
    </div>
  );
};

export default Player;

Here, ({ setPlayerHand }) is a prop that is coming from our parent component App.js. The function setHand() receives the option and passes it down to the setPlayerHand(), which then sets the playerHand in App.js to the received option. e.target.id gets the id which you have assigned in your divs id=’Rock’.
The options will be three different buttons that initiate setHand() when the player clicks the button onClick={setHand}. The class names are for styling purposes.

The Game component

Create a final component called Game.jsx. In the Game component, you will create a function to choose a random hand for the computer. This is where you will add the results conditions, i.e. among two hands which will beat the other and keep on track of the scores.

const Game = ({ score, playersHand, setScore }) => {
  const [result, setResult] = useState('');
  const [computerHand, setComputerHand] = useState('');

  const setHand = () => {
    const options = ['Rock', 'Paper', 'Scissors'];
    const hand = Math.floor(Math.random() * 3);
    setComputerHand(options[hand]);
  };

  const draw = () => {
    if (computerHand && playersHand === computerHand) {
      setResult('Draw');
    } else if (playersHand === 'Rock') {
      if (computerHand === 'Scissors') {
        setResult('You Win');
        setScore(score + 1);
      } else if (computerHand === 'Paper') {
        setResult('You Lose');
        setScore(score - 1);
      }
    } else if (playersHand === 'Paper') {
      if (computerHand === 'Scissors') {
        setResult('You Lose');
        setScore(score - 1);
      } else if (computerHand === 'Rock') {
        setResult('You Win');
        setScore(score + 1);
      }
    } else if (playersHand === 'Scissors') {
      if (computerHand === 'Paper') {
        setResult('You Win');
        setScore(score + 1);
      } else if (computerHand === 'Rock') {
        setResult('You Lose');
        setScore(score - 1);
      }
    }
  };

  useEffect(() => {
    draw();
  }, [computerHand]);

  return (
    <div className='game'>
      <div className='result'>
        {result && (
          <>
            <h2 className='win'>{result === 'You Win' && result}</h2>
            <h2 className='lose'>{result === 'You Lose' && result}</h2>
            <h2 className='draw'>{result === 'Draw' && result}</h2>
          </>
        )}
      </div>
      <div className='hands'>
        <p className='player'>{playersHand}</p>
        <p className='computer'>{computerHand}</p>
      </div>
      <button className='play-again' onClick={setHand}>
        Play
      </button>
    </div>
  );
};

export default Game;

Let's break this down. First, receive the props passed from the App component like = ({ score, playersHand, setScore }) =>. Then, you will use the useState hook to store the computer's hand and the result. The setHand() in this component sets the hand of the computer. You give it options, and the hand variable use the Math.random() trick, which gets a number between 0-3. options[hand] get an option from the array, and then the setComputerHand updates the state of the computer’s hand.

You then create a function called draw(), which compares the player's hand and the computer's hand and sets the result and the score. You receive the score and setScore from the App component. When the player wins, setScore(score + 1) updates the state of the score in your App.js. The Scoreboard then receives the updated state of score.

Later, in your JSX, you have a <button> called Play which runs the setHand function when clicked. So every time you hit the Play button, it updates the state of computerHand.

The useEffect hook also plays a vital role in this app. You have added the draw() function inside the useEffect, and in the dependency array, you have added computerHand. This means running the draw() function only when the computerHand state updates. So, whenever you hit the Play button, it updates the computer’s hand, which means it will run the useEffect hook, which runs draw() and draw gives the result and updates the score.

In JSX, we just render our variables in different HTML elements.

{
  result && (
    <>
      <h2 className='win'>{result === 'You Win' && result}</h2>
      <h2 className='lose'>{result === 'You Lose' && result}</h2>
      <h2 className='draw'>{result === 'Draw' && result}</h2>
    </>
  );
}

If you have a result, then you will return this fragment. And you will only render out a single h2 element that matches the result.

Styling

The CSS is straightforward for the app, which you can find here, but feel free to write your own, and I encourage you to write your styles yourself. It can be a good practice.

Conclusion

Final App And there you have your Rock, Paper and Scissors app built using React. Once you get comfortable passing down props to different components, it makes it easier to understand, and you can start doing a lot more cool stuff in React. I hope you enjoyed and learned something from this tutorial.

All the best, and keep learning!

Dec 06, 2022