Posted by: Zeeshan Amjad | September 22, 2023

Dice simulation using Redux


We created a dice simulation program using flux design pattern here https://zamjad.wordpress.com/2023/09/10/flux-design-pattern-using-typescript-in-react/

Now let’s try to create a same program, but this time using one of the very popular state management library Redux.

Let’s first install the redux using the following npm command on the terminal

npm install redux react-redux

The main concept is similar to what we did using the flux design pattern. For simplicity, I am going to write almost all the code in one file using JavaScript, instead of TypeScript. It is not a good practice to put everything in one file.

Let’s start with creating actions. We defined 4 action in our dice simulation application.

// define action types
const INCREMENT_DICE = 'INCREMENT_DICE';
const DECREMENT_DICE = 'DECREMENT_DICE';
const RESET_DICE = 'RESET_DICE';
const ROLL_DICE = 'ROLL_DICE';

// Create actions
const incrementDice = () => {
  return { type: INCREMENT_DICE };
}

const decrementDice = () => {
  return { type: DECREMENT_DICE };
}

const resetDice = () => {
  return { type: RESET_DICE };
}

const rollDice = () => {
  return { type: ROLL_DICE };
}

We are using two variable for our state, the number of dice and sum when we roll dice. Here is our initial state.

const initialState = {
  diceCount: 1,
  sum: 0,
};

Now we need to create a store. There should be only one redux store per application. It is a single source of truth for our application. We also need to define the function that describe what should we do with each actions. Here is a code to create function to do specific things based on action and create store.

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT_DICE:
      return {
        diceCount: state.diceCount + 1,
        sum: 0,
      };
    case DECREMENT_DICE:
      return {
        diceCount: state.diceCount - 1,
        sum: 0,
      };
    case RESET_DICE:
      return {
        diceCount: 1,
        sum: 0,
      }
    case ROLL_DICE:
      var sum = 0;
      for (var i = 0; i < state.diceCount; i++)
        sum += randomNumber(1, 6);
      return {
        diceCount: state.diceCount,
        sum: sum,
      }
    default:
      return state;
  }
};

export const store = createStore(counterReducer);

Here randomNumber is our own utility function to give us random number from minimum number using Math.random() method.

When we were not using redux in our previous version, we had to write dispatch function ourselves. Here redux is taking care of this for us. Here is JSX code to dispatch the action on each button.

<p><button onClick={() => dispatch(incrementDice())}>Increment</button>
<button onClick={() => dispatch(decrementDice())}>Decrement</button>
<button onClick={() => dispatch(resetDice())}>Reset</button></p>
<p><button onClick={() => dispatch(rollDice())}>Roll Dice</button></p>

We need to make one change in the App class. To use redux, we need to call our Dice component inside the Provider and specify what is our store. Here is complete code of our App file.

import React from 'react';
import './App.css';
import { Provider } from 'react-redux';
import Dice, {store} from './Dice';


function App() {
  return (
    <Provider store={store}>
      <div className="App">
        <Dice />
      </div>
    </Provider>
  );
}

export default App;

And here is our complete code of Dice.js file

import { useSelector, useDispatch } from 'react-redux';
import { createStore } from 'redux';

// define action types
const INCREMENT_DICE = 'INCREMENT_DICE';
const DECREMENT_DICE = 'DECREMENT_DICE';
const RESET_DICE = 'RESET_DICE';
const ROLL_DICE = 'ROLL_DICE';

// Create actions
const incrementDice = () => {
  return { type: INCREMENT_DICE };
}

const decrementDice = () => {
  return { type: DECREMENT_DICE };
}

const resetDice = () => {
  return { type: RESET_DICE };
}

const rollDice = () => {
  return { type: ROLL_DICE };
}

const initialState = {
  diceCount: 1,
  sum: 0,
};

const randomNumber = (min, max) => {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT_DICE:
      return {
        diceCount: state.diceCount + 1,
        sum: 0,
      };
    case DECREMENT_DICE:
      return {
        diceCount: state.diceCount - 1,
        sum: 0,
      };
    case RESET_DICE:
      return {
        diceCount: 1,
        sum: 0,
      }
    case ROLL_DICE:
      var sum = 0;
      for (var i = 0; i < state.diceCount; i++)
        sum += randomNumber(1, 6);
      return {
        diceCount: state.diceCount,
        sum: sum,
      }
    default:
      return state;
  }
};

export const store = createStore(counterReducer);

function Dice() {
  const noOfDice = useSelector(state => state.diceCount);
  const sum = useSelector(state => state.sum);
  const dispatch = useDispatch();

  return (
    <div>
      <h2>Dice Simulation Using Redux</h2>
      <p>Number of dices {noOfDice}</p>
      <p>Sum of rolling Dice {sum}</p>
      <p><button onClick={() => dispatch(incrementDice())}>Increment</button>
        <button onClick={() => dispatch(decrementDice())}>Decrement</button>
        <button onClick={() => dispatch(resetDice())}>Reset</button></p>
      <p><button onClick={() => dispatch(rollDice())}>Roll Dice</button></p>
    </div>
  )
}

export default Dice;

Here is an output of the program

Dice Simulation Redux

import { useSelector, useDispatch } from 'react-redux';
import { createStore } from 'redux';

// define action types
const INCREMENT_DICE = 'INCREMENT_DICE';
const DECREMENT_DICE = 'DECREMENT_DICE';
const RESET_DICE = 'RESET_DICE';
const ROLL_DICE = 'ROLL_DICE';

// Create actions
const incrementDice = () => {
  return { type: INCREMENT_DICE };
}

const decrementDice = () => {
  return { type: DECREMENT_DICE };
}

const resetDice = () => {
  return { type: RESET_DICE };
}

const rollDice = () => {
  return { type: ROLL_DICE };
}

const initialState = {
  diceCount: 1,
  sum: 0,
};

const randomNumber = (min, max) => {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT_DICE:
      return {
        diceCount: state.diceCount + 1,
        sum: 0,
      };
    case DECREMENT_DICE:
      return {
        diceCount: state.diceCount - 1,
        sum: 0,
      };
    case RESET_DICE:
      return {
        diceCount: 1,
        sum: 0,
      }
    case ROLL_DICE:
      var sum = 0;
      for (var i = 0; i < state.diceCount; i++)
        sum += randomNumber(1, 6);
      return {
        diceCount: state.diceCount,
        sum: sum,
      }
    default:
      return state;
  }
};

export const store = createStore(counterReducer);

function Dice() {
  const noOfDice = useSelector(state => state.diceCount);
  const sum = useSelector(state => state.sum);
  const dispatch = useDispatch();

  return (
    <div>
      <h2>Dice Simulation Using Redux</h2>
      <p>Number of dices {noOfDice}</p>
      <p>Sum of rolling Dice {sum}</p>
      <p><button onClick={() => dispatch(incrementDice())}>Increment</button>
        <button onClick={() => dispatch(decrementDice())}>Decrement</button>
        <button onClick={() => dispatch(resetDice())}>Reset</button></p>
      <p><button onClick={() => dispatch(rollDice())}>Roll Dice</button></p>
    </div>
  )
}

export default Dice;

Leave a comment

Categories