Simon Game with React and Redux

Victor Catalin Torac
5 min readOct 24, 2016

--

Hello, my name is Victor and today we will be looking togheter on how to create an Simon game using React and Redux.

If you are like me, an FreeCodeCamper and tryng to become an full stack developer, you know that in order to have the FrontEnd certificate, the last challenge is bulding an Simon Game.Here is how the finished pen will look like, well, almost, ours will be more simple.

The first question that comes in mind is “Do we need React and Redux for such an simple example?” and my answer is “NO, absolutly not, but is more fun that way and is an way to learn React and Redux, so why not”.

Enough talk, let’s start by creating an empty pen with an div container in the middle. Inside this flex-container we create 4 divs that will hold our colors, and an final div called center that will hold our controls. Since CSS and FlexBox is beyond the scope of this tutorial, below is an template pen with everything preseted, fork it and let’s start coding.

The first thing we do is adding 4 sounds and change the Colors components by adding an function that will trigger when we will have an “ONCLICK event”, since we have 4 sound we create 4 Colors component, each with an uniques sound.

So now , every time we click on the divs we play a sound. The last UI update we implement is an lightUp function that change the opacity of an div when it is clicked.

In the css portion just add an class named “anim” and give it an opacity of 0.2

The Game

User Story: I am presented with a random series of button presses.

//root js, outside of any Component
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
series = [] for(var i = 0; i < 24; i++) {series[i] = getRandomIntInclusive(0,3);}

The first challenge we encounter is how to make each sound play in sequence. We update once again our pen and add an button that starts the game and displays and plays 3 sequences, and we initiate the state with an empty series [] that we will use for storing our sequnces.

Now we need a way to store the user inputs and confront it with our sequnce, and in the same time we need to assure our user doesn’t click to early, so we give our divs an “unclickable = false” property that we remove after our sequnce is played.

//App componentconstructor(props) {
super(props);

this.state = {
series: [],
clickable: false
}
}
toggleClickable = () => {
this.setState({
clickable: !this.state.clickable
})
};

<Color1
name=’colors t-l’
lightUp={this.lightUp}
id=’tile0'
clickable={this.state.clickable} />
<Control
name='center'
series={this.state.series}
lightUp={this.lightUp}
toggleClickable={this.toggleClickable}
/>
........................................................
class Color1 extends Component {onClick = () =>{
if(this.props.clickable) this.props.lightUp(0)
};
}

Do the folowing for all four Colors components, and now the last thing we do is to change our playSeqfunction inside our Control Component

class Control extends Component {playSeq = (sequence) =>{
...
if(i >= sequence.length){
clearInterval(interval);
this.props.toggleClickable();
}
}, 1200)
};
...

Until now we have a decent game with 4 colors and a START button, but to really step up our developer level we will do the rest of the logic with Redux, cuz why not, we can, right? :)

Enter REDUX and ES6

So our logic until now was very simple, we used the inital state on our main App component and we pass down to it’s children all the props we needed. With Redux we abstract all the information outside of our component, inside a store object, and then acces that store inside the render() function of our App.

For simplicity sake here is an pen with everithing changed already.It has the same functionability like before only that is writen in a different way(Redux).

If this part confuses you, i reccomend this tutorial from the guy who created Redux, Dan Abramov. Let’s see what it is happening:

For first thing we abstract all the functions outside of our component,

...
function lightUp (tile) {

var toAnimate = $(“#tile”+tile);
toAnimate.addClass(“anim”);

soundBoard[tile].playbackRate = 0.7;
soundBoard[tile].play()

setTimeout(function(){
toAnimate.removeClass(“anim”);
}, 500);
};
...

then we create an initialStore object that it is used by the reducer function, so when we will create our store and call for the first time the store.getState() method it will return the initialStore, that it will be used by our Color components and Control.

Here is the code logic:

const initialStore= {
series: getSeries(),
clickable: false,
lightUp: lightUp,
count: 0,
clickable: false
};
function reducer (state = initialStore, { type, payload }) {
switch (type) {

case 't.change': {
return { ...state, clickable: payload };
}
default:
return state;

}
}
const store = createStore( reducer );class App extends Component{...render() {
let state = store.getState();
...
<Color4 name='colors b-r'
lightUp={state.lightUp}
id='tile3'
clickable={state.clickable}
/>
<Control
name='center'
series={state.series}
lightUp={state.lightUp}
/>
}
}

What is a Reducer? An reducer is an function that manages how the next state is calculated based on the previous state of the whole application and the action being dispatched.

Actions

If you look at our pen inside our Control we have this line of code

playSeq = (sequence) =>{
let i = 0;
var interval = setInterval( () =>{
this.props.lightUp(sequence[i]);
i++;
if(i >= sequence.length){
clearInterval(interval);
store.dispatch( clickable() ) }
}, 1200)
};

and in our actions sections we have this function

///////////////////////actions////////////////////
function clickable() {
return {
type: ‘t.change’,
payload: true
};
}
//////////////////////////////////////////////////////////////////

What this line of code does is to call the reducer function with the object returned from the action as the second parameter

function reducer (state = initialStore, { type, payload }) {

and then using the switch, modifies the state and then returns it to our App component because our App it subscribed for any store change in the componentWillMount() function.

componentDidMount () { 
store.subscribe(() =>
//each time the store will update we will trigger the render()
this.forceUpdate()
);
}

Finishing the GAME

So now using our actions and the switch inside our reducer() we implement the rest of the logic for our game.

We start with 3 colors, so we need an way to store our partialSequnce, so we update our initialStore by adding an partialS array

const initialStore= {
series: getSeries(),
partialSeries: [], ...

then we create an action(function that returns an object) called partialS that takes an array as an argument and pass it to the payload

function partialS(arr) {
return {
type: ‘t.partialS’,
payload: arr
}
}

finaly we update our switch inside our reducer()

function reducer (state = initialStore, { type, payload }) { 
switch (type) {
...
case 't.partialS' : {
return{ ...state, partialSeries: payload}
}
...

and that’s it. I have included an console log inside the App — render() so you can easily see the state object inside our store.

For you to realy learn, before continue reading, pls take a moment and think about how would you proceed from this moment on, knowing how actions and reducer are bind togheter, and idealy try to finish the game without any help.

I will not explain each step until the end, i finish this article by giving you the finished version of the pen, so you can split you’re screen and check the code.

Thank you for reading, hope this article was helpfull, good luck and bye.

--

--