Reflux Sweeper – React, Reflux And ImmutableJS Explained By Example

Reflux Sweeper – React, Reflux And ImmutableJS Explained By Example

Reading Time: 12 minutes

Recently I have been diving into the understanding of managing simple data structure when building simple Mines Sweeper game inspired by the React Sweeper project. I also used Facebook’s ImmutableJS library to manage my data structure. In this blog post I will describe,step by step, how I managed to build this app, and what led me to the decisions I took.

First, I will start with basic background on Flux. If until now we had ReactJS that handled the view, Flux is not a library, it is a concept, or maybe we can call it “data flow architecture on client side”. It is a complement concept that gives us the Model and the communication between UI and Model. The fastest coverage I can give is that the UI talks with the Model with Actions that invoked by UI. The Actions are delivered to the Dispatcher which is responsible to manage the logic of invoking the Actions on the Stores that affect the UI and it goes on and on… that sounds like completely gibberish but when you try to play with some implementations of this Flux concept you get the point pretty fast. Here’s some diagram taken from Flux page to show the flow of the data:

flux-simple-f8-diagram-with-client-action-1300w

Reflux is a simple library that implements Flux architecture. There are some implementations out there that honestly I haven’t tried (except of Redux), but what makes Reflux special is that it jumps over the concept of the Dispatcher (I will examine Redux in other post) and leaves the flux architecture even simpler to look like this:

First we’ll start with the file-system structure, logic and data structure.

  • The app is sitting under /app directory obviously.
  • App.js contains one single function that renders the app to the DOM with ReactDOM came with version 0.14 of React.
  • Utils.js includes the utillities I use to make two dimensional array or default initialized board etc.
  • Then we have the /assets dir which contains all dependencies and libraries I’m using such as : React, Reflux, Immutable, React-DOM, underscoreJS etc.
  • The source core code is under src and Grunt is compiling my files from ES6 to ES5 so browsers could read it properly.
  • Under /src we have /actions which contains single file Action.js that stores an array of actions (look for points in the end of the post).
  • Under /Components I store all app components (see description of the components below) – for this app: BoardPiece.js, GameBoard.js, ScoreBoard.js.
  • Under the /stores dir we have the 2 stores of the app GameStore.js, BoardStore.js.
  • Under /views dir I store the different views of the app and right now I have only one so we name it RefluxSweeper.js.
  • /public dir includes in /assets sub directory the compiled files, app.js – the application compiled es5 and minified.
  • infrastructure.js – compiled file with all libraries in single file (see concat for grunt).

Logic:
This part is the least important in my opinion in here and if you want to learn more about it just google “mines sweeper logic” or something and boom you have tons of information and methods. I want to concentrate on the communication between the components using the Flux architecture.

Data Structure && Reflux

2 Main components:

  • ScoreBoard – the configuration part of the app, new game, change level, change board size etc.
  • GameBoard – the board itself which holds all of the board pieces

Both of them need to communicate so when something changed in the GameBoard it affects the ScoreBoard and vice versa, for example right click on the BoardPiece will set flag to it and reduce flag count from the ScoreBoard. We can do it by passing functions through the props of the element BUT when your app will grow trust me you don’t want to pass the your function by props upstream the hierarchy tree of the elements, it starts to mess very quickly. What we can do is (and here comes the magic of the Flux, drums…) fire an action that the store listens to, and then the store notifies all components listen to that store.

You can notice that notification that comes from the BoardPiece is not notifying its parent component GameBoard but fires action that goes directly to the GameStore. (events firing and event listeners, sounds familiar?)

  • BoardPiece – every tile on board is represented by this component, it manages the state of single tile over the game life cycle.

Stores:
BoardStore – as said above here I listen to all changes made on the board such as revealing tiles, marking them as flags, winning game, losing game, etc. If you are familiar with the MVC methodology so we can say that is the mutation of controller and model, it is very intuitive and simple, you listen to action comes from the view and do you thing in the store, then update view that something happen.

GameStore – the store that is in charge of the state of the game itself, are you started the game? have you won? have you lost? the dimensions of the board, the level and etc. Some thing interesting that I figured out is that you can actually listen to changes that occur on other store and act accordingly, the actions that you are listening to are the same actions that the BoardStore listens to, so if they listen to a same action (onNewGame for example), they each do what they supposed to do. This gives you some kind of “thready” feeling and it is awesome power of Reflux.

Points:

  1. Actions in one place – well, there is not a good case of why separate your actions into few files, especially if you have a small app. You can make separation inside the Actions.js by comments if you really want. These actions inside this file are store in an array of strings.
  2. State – state must be managed in the components. I tried to manage the state in the stores but this led to some wrong use of react, I had to FORCE render the component because I hadn’t a way to determine if state changed but to get notation from the store and then render the component manually, this is a bad idea. The state of a component should contain only properties that you know that are going to change through the life cycle of the component and that will affect the view of it, such as isFlag, or isRevealed etc.

code is written in half ES6 and half ES5, sorry about that, it will be fixed as soon as possible :), please feel free to comment what do you think about this simple app, improvements etc.

References:

  1. https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture – great flux explanation
  2. https://www.youtube.com/watch?v=wA98Coal4jk – great talk about ImmutableJS and building a mines sweeper with it.
  3. https://ochronus.com/react-reflux-example/ – another good reflux by example
  4. http://blog.krawaller.se/posts/the-reflux-data-flow-model/ – explanation of Reflux data model
  5. http://reactjsnews.com/building-components-with-react-js-and-flux/
  6. https://medium.com/swlh/the-case-for-flux-379b7d1982c6#.tg83wo7fo