Skip to content

Instantly share code, notes, and snippets.

@misterussell
Created April 18, 2018 22:30
Show Gist options
  • Save misterussell/b780b4292267bac1e7d0d2b8587a6837 to your computer and use it in GitHub Desktop.
Save misterussell/b780b4292267bac1e7d0d2b8587a6837 to your computer and use it in GitHub Desktop.
4 18 18 Blog Post

Conway's Game of Life in JavaScript - Part VII - Stateless Components

Woah Nellie! That was a jump.

In this weeks exploration of JavaScript through Conway's Game of Life I've moved away from using create-react-app in favor of a less bottlenecked bootstrap simple-react-app from @francesco.agnoletto.

Why switch now, after I did all that work? Because I wanted to check out MobX and I couldn't get decorators to work in create-react-app without ejecting. There are a few other reasons I decided to move away from create-react-app as well, but they aren't relevant to this project.

Major Change - Stateless Components

I'm always reading that it is better to have stateless components when you can. Considering that this project isn't making async requests to external API's I figured it would be a good place to get some practice creating components without state. Overall - there isn't a lot going on in the app. There are some buttons and a grid of divs. Well, actually, there is a lot going on to get just those things. Credit is due! I've been reworking this over and over. It took me about 2 days to get everything stateless and moved into MobX stores. And BOY do I like it.

Benefits?

Overall I like how much cleaner the main game component has become. I was able to minimize it down to the grid, buttons (with relevant click handlers), and a containing div. No additional functions for changing the shape of data, or updating it. That is all handled in the stores.

The gameboard component really only needs to know one thing to correctly render itself. An array of 0's and 1's. The number of columns and rows, and the size of the cells can be derived from that. Changing the number of indices in the stored array and voila, updates to the dom.

The interactions with the different pieces of the component only need to know whether or not the game is already running. If it's running you shouldn't be able to click anything except to stop the game.

I suppose it is debatable whether or not my interval should live on the component, but as long as the interval is cleared at the store level if the observable is no longer observed, that should take care of things?

I have separated the Game of Life into three stores:

  1. The Grid UI - This calculates the dynamic sizing of the grid component.
  2. The Gameboard State/Logic - This calculates how many cells should be present, what their values should be, and what may change about their values.
  3. The Gameplay State - This tracks whether things are moving along, or stopped.

I'm not integrating the Grid UI into the Gameboard Store, but it does rely on knowing how many cells are currently available to generate it's specs. As it is purely a visual structure, I fell this is appropriate.

// image

The Gameplay logic also reaches out to the Gameboard Store, as it needs to set an interval to keep the game running while cells are alive, forcing the visual to re-render. I'm able to reach between stores because each store is bound to the rootStore, parent store.

// image 2

The Gameboard then controls itself with just a few key pieces of information. I define the minimum number of rows/cols that the grid can have, the number of rows/cols that the user may have added and a hashMap that is used to generate the subsequent cell's values.

// image 1

Most of my other components haven't really changed much. At least I seem to have been on the right track. Here's a comparison of the Grid Component before and after. Overall there's some syntactical differences, but mostly stays the same :

Before: // image 3

After: // image 4

Hmm...

I am treating my stores as collections and models to try to keep some form of integrity into the way I organize my files/data, but I think I need to investigate best practices a little more for this.

Flaws?

There are flaws in everything. We are developers. Flaws are our bread and butter?

After refactoring this into a mixture of pure function components and bare-bone class extensions the heavy lifting immediately feels less functional to me. I was using classes(factories really) to handle data manipulation in the earlier version of this, but I was freezing things my factories produced. This made things not very mutable. I liked that. I need to continue to refactor the newer class stores to get them back to how I had it before.

Linting Rules

This didn't end up just being a copy and paste voila! The linting rules from AirBnB's style guides had me rewriting a lot of code. I used their style-guides prior to adding the rules to my linter but this really put the foot down on keeping things consistent

  • It put my over-use of nested ternaries in check.
    • I did spend a lot of time thinking through semantic ways to name nested ternaries, so I don't live this rule but will stick with it for now.
  • Drastic overhaul of arrow functions
    • I didn't realize how inconsistent I was with {}'s.

What's next?

I do not like the way that I have to pass props into my link. I need to spend some time reading up on the Context API to get past this.

Check out where I started on this project to see how much it has changed! Part I.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment