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.
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
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
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.
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.
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.
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.
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.
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.
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!