DEV Community

Cover image for How to Make a Best Dice Roll React Component
Michael J. Larocca
Michael J. Larocca

Posted on • Originally published at selftaughttxg.com

How to Make a Best Dice Roll React Component

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!


TXG-95


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";
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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 }) {

  });
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
      }
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }, []);
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

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>
    </>
    )
  }
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The finished project

Here are the links to the finished project:


Best Low Dice Roll component


My other related articles


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.


Are you now skilled in creating a "best low-roll" dice React component for your projects? Have you created similar components using useState and useEffect hooks in your React development? Please share the article and comment!

Top comments (0)