In this article, we build a React best dice roll game component. From your main App file, you will learn how to pass game start and end props to control it and gain skills for your original projects!
Introduction
In this article, we create a React component that counts and then stores the best dice rolls in a game in local storage. To be clear, the best dice rolls are the least amount of rolls it takes to complete the game.
I intend to use this component in an upcoming React Tenzi game, along with a best-time React component I created.
Notes: For the best dice roll React component, I created a variable named yourAwesomeGameName*. The purpose of this variable is to differentiate the best dice rolls that are stored in local storage. For example, you will set the value of the variable **yourAwesomeGameName to the name Tenzi for a Tenzi game, Yahtzee for a Yahtzee game, and Farkle** for a Farkle game.*
const yourAwesomeGameName = "yourAwesomeGameName";
The saveBestDiceRoll function saves your best dice roll for each game you use this component for, respectively.
function saveBestDiceRoll(bestDiceRoll) {
localStorage.setItem(`${yourAwesomeGameName}-BestDiceRoll`, bestDiceRoll);
}
Here is an example of what each yourAwesomeGameName variable would look like in local storage when using it in three different React apps:
KEY
Tenzi-BestDiceRoll
Yahtzee-BestDiceRoll
Farkle-BestDiceRoll
Note: We will be focusing on learning React code, not CSS. However, feel free to clone the project or copy the CSS code.
Start, Roll Dice, and End buttons
We use the Start, Roll Dice, and End buttons to simulate the actions within the game you are using the component for. When this component is integrated into your React game app, these buttons are not to be rendered. These actions will be controlled in the main JSX app and passed to the component using props.
Setting up the environment
First, we need to set up our coding environment.
The React environment
For this project, I used the VS Code editor to create a React app with Vite. Afterward, I converted it into a GitHub repository and deployed it on Netlify.
If you would like to learn how to set up a local React development environment, I wrote the following two beginner-friendly articles:
Building the Best Low Dice Roll component
At the top of the App JSX file, we will import the necessary hooks:
useState
useEffect
import { useState, useEffect } from "react";
Best Low Dice Roll function
We will be writing our code inside of a function called BestLowDiceRoll, which is located in the components folder ( which is inside of the src folder).
The gameStarted*, **gameEnded*, *setGameStarted*, *setGameEnded**, are props that are passed in from the main App.jsx file.*
function BestLowDiceRoll({ gameStarted, gameEnded, setGameStarted, setGameEnded }) {
});
Inside the App function, we initially set up the variables.
Variables initialized:
currentDiceRoll: The number of dice rolls in the current game
gameEndDiceRoll: The number of dice rolls when the game ends
gameBestDiceRoll: The lowest number of dice rolls to complete the game
yourAwesomeGameName: The name of the game to differentiate best dice rolls in local storage
const [currentDiceRoll, setCurrentDiceRoll] = useState(0);
const [gameEndDiceRoll, setGameEndDiceRoll] = useState(0)
const [gameBestDiceRoll, setGameBestDiceRoll] = useState(0);
const yourAwesomeGameName = "yourAwesomeGameName";
The reset dice function
The resetDice function sets the currentDiceRoll variable back to 0, which means it resets the number of dice rolls in the current game.
function resetDice() {
setCurrentDiceRoll(0);
}
The roll dice counter function
The rollDiceCounter function increases the currentDiceRoll by 1 each time it's called, updating the number of dice rolls in the current game.
function rollDiceCounter() {
setCurrentDiceRoll(prev => prev + 1);
}
The get best dice roll function
The getBestDiceRoll function retrieves the best dice roll (lowest number of rolls to complete the game) from local storage for the specified game and returns it as an integer. If no best dice roll is stored, it returns Infinity.
function getBestDiceRoll() {
const storedBestDiceRoll = localStorage.getItem(`${yourAwesomeGameName}-BestDiceRoll`);
return storedBestDiceRoll ? parseInt(storedBestDiceRoll, 10) : Infinity;
}
The save best dice roll function
The saveBestDiceRoll function saves the best dice roll (lowest number of rolls to complete the game) to local storage for the specified game.
function saveBestDiceRoll(bestDiceRoll) {
localStorage.setItem(`${yourAwesomeGameName}-BestDiceRoll`, bestDiceRoll);
}
The update best dice roll function
The updateBestDiceRoll function compares the gameEndDiceRoll with the current gameBestDiceRoll. If the gameEndDiceRoll is less than the gameBestDiceRoll and not equal to 0, it updates the gameBestDiceRoll state and saves it to local storage using the saveBestDiceRoll function.
function updateBestDiceRoll() {
if (gameEndDiceRoll < gameBestDiceRoll && gameEndDiceRoll !== 0) {
setGameBestDiceRoll(gameEndDiceRoll);
saveBestDiceRoll(gameEndDiceRoll);
}
}
The start game function
The startGame function sets the gameStarted state to true and the gameEnded state to false, indicating that a new game has begun.
function startGame() {
setGameStarted(true);
setGameEnded(false);
}
The end game function
The endGame function sets the gameEnded state to true and gameStarted state to false, indicating that the game has ended. It then updates the gameEndDiceRoll state with the currentDiceRoll value. The function checks if the currentDiceRoll is less than the bestDiceRoll, and if so, saves the currentDiceRoll as the new bestDiceRoll in local storage and updates the gameBestDiceRoll state.
function endGame() {
if (!gameEnded) {
setGameEnded(true);
setGameStarted(false);
setGameEndDiceRoll(currentDiceRoll);
const bestDiceRoll = getBestDiceRoll();
if (currentDiceRoll < bestDiceRoll) {
saveBestDiceRoll(currentDiceRoll);
setGameBestDiceRoll(currentDiceRoll);
}
}
}
The useEffect Hooks
This useEffect Hook retrieves the best dice roll from local storage when the component mounts and sets the gameBestDiceRoll state with that value. The empty dependency array ensures this effect runs only once.
useEffect(() => {
const bestDiceRoll = getBestDiceRoll();
setGameBestDiceRoll(bestDiceRoll);
}, []);
This useEffect Hook listens for changes in the gameStarted and gameEnded state variables. If gameStarted becomes true, it calls the resetDice function to reset the currentDiceRoll to 0. If gameEnded becomes true, it calls the updateBestDiceRoll function to compare and update the best dice roll if the current game's dice roll count is lower.
useEffect(() => {
if (gameStarted) {
resetDice();
} else if (gameEnded) {
updateBestDiceRoll();
}
}, [gameStarted, gameEnded]);
Render the Component
This rendered element displays the currentDiceRoll and gameBestDiceRoll values in a section, and three buttons (Start, Roll Dice, and End) to control the game flow.
When the game starts, the currentDiceRoll is reset to 0. The Roll Dice button increments the currentDiceRoll count, and the End button compares and updates the gameBestDiceRoll if the current game's dice roll count is lower. The Start and Roll Dice buttons are disabled when the game is not active, and the End button is disabled when the game is active or not yet started.
return (
<>
<section className="best-low-dice-roll">
<div className="best-low-dice-roll-inner-border">
<div>Dice Rolls: {currentDiceRoll}</div>
</div>
<div className="best-low-dice-roll-inner-border">
<div>Best Rolls: {gameBestDiceRoll === Infinity ? '---' : gameBestDiceRoll}</div>
</div>
</section>
<button onClick={startGame} disabled={gameStarted}>
Start
</button>
<button onClick={rollDiceCounter} disabled={!gameStarted || gameEnded}>
Roll Dice
</button>
<button onClick={endGame} disabled={!gameStarted || gameEnded}>
End
</button>
</>
)
}
Export the best dice roll React component
Finally, we export the best dice roll React component so that we can import it into the App.jsx file.
export default BestLowDiceRoll;
Here is the complete best low dice roll component
import { useState, useEffect } from "react";
function BestLowDiceRoll({ gameStarted, gameEnded, setGameStarted, setGameEnded }) {
const [currentDiceRoll, setCurrentDiceRoll] = useState(0);
const [gameEndDiceRoll, setGameEndDiceRoll] = useState(0)
const [gameBestDiceRoll, setGameBestDiceRoll] = useState(0);
const yourAwesomeGameName = "yourAwesomeGameName";
function resetDice() {
setCurrentDiceRoll(0);
}
function rollDiceCounter() {
setCurrentDiceRoll(prev => prev + 1);
}
function getBestDiceRoll() {
const storedBestDiceRoll = localStorage.getItem(`${yourAwesomeGameName}-BestDiceRoll`);
return storedBestDiceRoll ? parseInt(storedBestDiceRoll, 10) : Infinity;
}
function saveBestDiceRoll(bestDiceRoll) {
localStorage.setItem(`${yourAwesomeGameName}-BestDiceRoll`, bestDiceRoll);
}
function updateBestDiceRoll() {
if (gameEndDiceRoll < gameBestDiceRoll && gameEndDiceRoll !== 0) {
setGameBestDiceRoll(gameEndDiceRoll);
saveBestDiceRoll(gameEndDiceRoll);
}
}
function startGame() {
setGameStarted(true);
setGameEnded(false);
}
function endGame() {
if (!gameEnded) {
setGameEnded(true);
setGameStarted(false);
setGameEndDiceRoll(currentDiceRoll);
const bestDiceRoll = getBestDiceRoll();
if (currentDiceRoll < bestDiceRoll) {
saveBestDiceRoll(currentDiceRoll);
setGameBestDiceRoll(currentDiceRoll);
}
}
}
useEffect(() => {
const bestDiceRoll = getBestDiceRoll();
setGameBestDiceRoll(bestDiceRoll);
}, []);
useEffect(() => {
if (gameStarted) {
resetDice();
} else if (gameEnded) {
updateBestDiceRoll();
}
}, [gameStarted, gameEnded]);
return (
<>
<section className="best-low-dice-roll">
<div className="best-low-dice-roll-inner-border">
<div>Dice Rolls: {currentDiceRoll}</div>
</div>
<div className="best-low-dice-roll-inner-border">
<div>Best Rolls: {gameBestDiceRoll === Infinity ? '---' : gameBestDiceRoll}</div>
</div>
</section>
<button onClick={startGame} disabled={gameStarted}>
Start
</button>
<button onClick={rollDiceCounter} disabled={!gameStarted || gameEnded}>
Roll Dice
</button>
<button onClick={endGame} disabled={!gameStarted || gameEnded}>
End
</button>
</>
)
}
export default BestLowDiceRoll;
Here is the complete App.jsx file
import { useState } from 'react'
import BestLowDiceRoll from '../src/components/BestLowDiceRoll';
import './App.css'
function App() {
const [gameStarted, setGameStarted] = useState(false);
const [gameEnded, setGameEnded] = useState(false);
return (
<BestLowDiceRoll
gameStarted={gameStarted}
gameEnded={gameEnded}
setGameStarted={setGameStarted}
setGameEnded={setGameEnded}
/>
)
}
export default App
The finished project
Here are the links to the finished project:
My other related articles
Learn Local Storage in React: Create a Light and Dark Theme Switcher Application
Creating a True/False Toggle in React with useState Hook for Beginners
Conclusion
In this article, we learned how to create a "best low-roll" dice React component that you can use in your projects. By importing this React component from the components folder into your main App file, you are able to control it by passing game start and end props.
By using local storage, you can save the user's best dice roll for multiple React game projects by utilizing the "yourAwesomeGameName" variable, which distinguishes each one saved in local storage.
We also created various functions and learned how to use the useState and useEffect React hooks, as well as how to render the component. All of these are essential skills needed for React development!
Now it's time to roll the dice! Enjoy enhancing your React projects by incorporating this component and creating your own unique components using the newly acquired React skills you've gained!
Let's connect! I'm active on LinkedIn and Twitter.