To understand state and props better lets make this Dice roller app!
we will be adding some styling and animation as well!
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;
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;
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
how to access these icons:
1.so for now we can insert the link inside public/index.html somewhere in
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.7.0/css/all.css"
integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ"
crossorigin="anonymous"
/>
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;
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}`} />
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;
}
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"}
}
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"]
};
5.Button time,
Roll Dice!
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)];
}
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})
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);
}
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!}
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);
also set True value when we do he setState
this.setState({ die1: newDie1, die2: newDie2, rolling: true });
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>
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);
}
}
we can add a separate class for this wobble to also add duration
.shaking {
animation-name: wobble;
animation-duration: 1s;
}
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>
);
}
}
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;
I hope you had fun with this RollDice App
Top comments (0)