DEV Community

Cover image for DICE ROLLER APP WITH STATE AND PROPS
Kimia Kamrava
Kimia Kamrava

Posted on

DICE ROLLER APP WITH STATE AND PROPS

To understand state and props better lets make this Dice roller app!
we will be adding some styling and animation as well!
roll_dice

How to start

let's go step by step!
1.create-react-app dice
2.cd dice
3.npm start
to start this app we can start with a dumb die(stateless die).

Dumb Die

By creating a Die component and rendering a Die let's check if everything works fine!

import React, { Component } from"react";

class Die extends Component {
 render() {
   return<h1>DIE!</h1>;
   }
}
export default Die;
Enter fullscreen mode Exit fullscreen mode

to see the Die we need to render Die in App.js

import React, { Component } from "react";
import Die from "./Die";
import "./App.css";

class App extends Component {
  render() {
    return (
      <div className='App'>
        <Die />
      </div>
    );
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

now we can see Die on localhost.

Adding Die icons will rock, checkout this website and install some Die icons with style and className . we can edit and play more with it.
fontawesome:dice icon link

Untitled

how to access these icons:
1.so for now we can insert the link inside public/index.html somewhere in

to access Die icons.
 <link
      rel="stylesheet"
      href="https://use.fontawesome.com/releases/v5.7.0/css/all.css"
      integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ"
      crossorigin="anonymous"
    />
Enter fullscreen mode Exit fullscreen mode

to see the icons let's insert the icon inside Die component and we hard-coded the className from the link to see the Die. The problem is we can see the Die dynamically which we have a solution for , to understand better we will go step-by-step.

import React, {Component } from "react";

class Die extends Component {
render() {
  return <i className='fas fa-dice-one' />;
  }
}
export default Die;
Enter fullscreen mode Exit fullscreen mode

There we go now we have the first icon showing up our little black showing number one die as we hard coded.So if in our App.js we put . we cant see die face five to show the dice dynamically this is the solution:
The fas fa-dice- is always the same. to change the face we can go with the famous ${}.

 return <i className={`fas fa-dice-${this.props.face}`} />
Enter fullscreen mode Exit fullscreen mode

since we gave our App.js our desired face like five we will get our

styling

To have the Die a little bit larger in Die.css component we will have:

.Die {
font-size :10cm;
padding:0.25cm;
color:purple;
}
Enter fullscreen mode Exit fullscreen mode

Hint: don't forget to import Die.css inside our Die.js componenet.

DUMB DICE DONE NEXT STOP ROLL THE DICE

The fun part starts right here :
1.lets make RollDice.js file
2.so imagine we open this app and we want to see two dice facing number one. like the theater when we enter will already see the set. YES SET! this is where state comes ... so the state of the dice at first will be always one. we can write that in code!

class RollDice extends Component {
  constructor(props) {
    super(props);
    this.state = { die1: "one", die2: "one"}
  }
Enter fullscreen mode Exit fullscreen mode

Untitled

By importing Die from '/.Die' now we can return


and we will just see two dice showing number one!
since we didnt set any states meaning we didnt update the state.
3.In App.js we can now import the RollDice instead of rendering the Die face="five"
4.Now what we need to do?lets start by defining an array of all the sides or faces with

defaultProps


why? it doesn't make sense to put this inside the state since it's not going to change and it doesn't have to be in props either. now I Know the class Component with => will do this automatically but let's learn step b step:D
 static defaultProps = {
    sides: ["one", "two", "three", "four", "five", "six"]
  };
Enter fullscreen mode Exit fullscreen mode

5.Button time,

6.now what is roll? we need a roll function .inside roll function we will need to pick 2 new rolls and set state with new rolls.to pick the 2 new rolls we need to (Math.random() * this.props.sides.length) so this.props is the access to the array of default props sides,but there is a problem here that is not integer so we will need floor

 roll(){
const newDie1=this.props.sides
[Math.floor(Math.random() * this.props.sides.length)];
const newDie2=this.props.sides
[Math.floor(Math.random() * this.props.sides.length)];
}
Enter fullscreen mode Exit fullscreen mode

7.How to update the state? imagine the scene of the theater is changing so the curtains are down and now people from backstage are trying to set a new scene and everything updates this is where setState comes:D the people from backstage will bring the new Die and in here its random so:

this.setState({die1: newDie1, die2: newDie2})
Enter fullscreen mode Exit fullscreen mode

But now when we Roll the Dice it doesnt know what is (this.props) inside const newDie. we can define that .

class RollDice extends Component {
  static defaultProps = {
    sides: ["one", "two", "three", "four", "five", "six"]
  };
  constructor(props) {
    super(props);
    this.state = { die1: "one", die2: "one"};
    this.roll = this.roll.bind(this);
  }
Enter fullscreen mode Exit fullscreen mode

HINT

: When we call this.setState the whole render component re renders and since we have two other Die components inside the component they will also re render and have new value passed in as in props called face.

Animation

1.To get the Rolling Dice inside this.state we will add another property rolling which will have the value false .because we dont need to see that first and inside roll function this.setState after updating the faces we will have the rolling:true,but now when we click on the button it will stay true .
2.Now onClick of this roll we want to say if it is rolling what do we want to see on button?Rolling otherwise Roll Dice.

 <button onClick={this.roll}> 
{this.state.rolling? 'Rolling...' : "RollDice!}
Enter fullscreen mode Exit fullscreen mode

Now it will stay on Rolling ...how can we solve this?one solution is giving it a timer we can say wait one second, the set rolling to false in roll()

  setTimeout(() => {
      this.setState({ rolling: false });
    }, 1000);
Enter fullscreen mode Exit fullscreen mode

also set True value when we do he setState

this.setState({ die1: newDie1, die2: newDie2, rolling: true });
Enter fullscreen mode Exit fullscreen mode

And now we can still click on the button while Rolling..how to stop that?
There is an attribute called disabled for button

  <button onClick={this.roll} disabled={this.state.rolling}>
          {this.state.rolling ? "Rolling..." : "Roll Dice!"}
        </button>
Enter fullscreen mode Exit fullscreen mode

Remember if we only give true value to disabled it will stay disabled permenantly and we cant click it!

Jiggle Jiggle Time

in our Die.css we will add a wobble keyframe which has a rotation and moving left and right :

@keyframes wobble {
  from {
    transform: translate3d(0, 0, 0);
  }

  15% {
    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
  }

  30% {
    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
  }

  45% {
    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
  }

  60% {
    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
  }

  75% {
    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
  }

  to {
    transform: translate3d(0, 0, 0);
  }
}

Enter fullscreen mode Exit fullscreen mode

we can add a separate class for this wobble to also add duration

.shaking {
  animation-name: wobble;
  animation-duration: 1s;
}
Enter fullscreen mode Exit fullscreen mode

How to send this shaking when we are rolling the dice and not refreshing or at the beginning? yes => state.
In RollDice we need to add the prop rolling inside the Die

 render() {
    return (
      <div className='RollDice'>
        <div className='RollDice-container'>
          <Die face={this.state.die1} rolling={this.state.rolling} />
          <Die face={this.state.die2} rolling={this.state.rolling} />
        </div>
        <button onClick={this.roll} disabled={this.state.rolling}>
          {this.state.rolling ? "Rolling..." : "Roll Dice!"}
        </button>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Also in Die componenet we will be needing another class to check conditionally check based off this stop prop start rolling.if it was rolling we want to apply class shaking othere wise nothing.

class Die extends Component {
  render() {
    return (
      <i
        className={`Die fas fa-dice-${this.props.face} ${this.props.rolling &&
          "shaking"}`}
      />
    );
  }
}
export default Die;
Enter fullscreen mode Exit fullscreen mode

I hope you had fun with this RollDice App

thanks to Colt Steele


Oldest comments (0)