At SoundHound, our front-end stack is heavily composed of React Components. About 8 months ago, we naturally began experimenting with Flux implementations as well since the two work well together.
We started with the generic Flux implementation, then moved to Reflux, and finally settled on NuclearJS. This post will explain some of our rationale behind what NuclearJS is, and why we love building with it.
Note: NuclearJS is overkill for small applications, but it will save you a lot of headache in large client-side production applications. Ok let’s get started.
what IS Flux?
There are plenty of good tutorials explaining Flux (and a few bad ones too), so I won’t spend too long on it.
Flux is just a word used to describe a certain type of data flow through your application.
When implementing Flux, data flows one way through your app, making it easier to debug. The following diagram is often used to explain the data flow.
But what does that picture mean? I like using examples to explain things so I’ll try to do that here.
Imagine you are building a category view like you see inside the Chrome Web Store (see picture below).
According to Generic Flux, here’s how data would flow through out this application:
- On page load, some React component would be mounted. The React component would be listening to a CategoryStore’s change event. Initially the CategoryStore has nothing; it’s an empty array.
- The React component would call an Action. Something like (Actions.loadCategories())
- Actions.loadCategories() would call an API to get a JSON representation of the categories, and send it to a Store where it would be saved as an array. In this case the categories are everything you see on the left side menu (Home, Popular, Trending, etc.).
- The store being updated would call the React Component’s render() method. This would render all those categories in a nice list.
- Something similar would happen with the right side of the page, which is dependent on what category you have selected.
NuclearJS is a Flux implementation centered around a few important paradigms. I’ll go over them in detail below, as they are all important, and played a role in us choosing this framework.
Note: I’m ignoring a lot of good stuff in my short list below. For the full lowdown on how NuclearJS differs from other Flux implementations, read this.
Many Small Stores
I’ll start with stores. While developing with NuclearJS, we found that it encourages creating many small Flux Stores.
As an example, let’s take a look at that Chrome Web Store screenshot again. We can separate data into a couple of stores:
- AppListStore (stores a list of all the applications you see on the screen)
- MenuStore (Stores the different menu items in an array Home, Popular, Trending, etc.)
- SelectedMenuStore (This can store the selected menu item, Trending in this case).
- SearchTermStore (This can store the search query that you can enter into the box on the top-left).
The data in these stores is independent from each other. As your user interacts with your app, your components fire actions that modify the data inside one or more stores.
Benefit: We found that having many small stores increases maintainability, as the data structure within each store is extremely simple. We stay away from storing nested objects inside the same store. We usually separate it out into another store.
Speaking of data, NuclearJS does not have a way to explicitly get data out of stores. It has this awesome concept called Getters.
A getter is a function that can take data from one or more stores, transform it, and return it to your component as state. This is a very powerful concept.
For example, let’s say we have a store with Applications (AppListStore), and when a user types a search query in, we want to modify the visible applications. We could write a Getter to do this, as demonstrated in
In the React component that displays the Application Grid View, we could watch to the
filteredApplicationList variable via the component’s state. You can see what this would look like in the
Benefit: Getters are an amazing way to gather data from multiple stores, and transform them into what your user interface needs. Furthermore, NuclearJS does all the heavy lifting so if your store changes, your getters are automatically re-calculated, and your components are automatically re-rendered.
Getters help keep your stores and components extremely simple, as the former just stores data, and the latter just displays it. They are also extremely reusable. We have multiple components that listen to the same getters, which gives us close to 100% code re-use.
The concepts above would not be possible without Immutable Data Structures, which NuclearJS fully embraces. The concept behind Immutability is well documented, so I’ll explain why it works so well.
NuclearJS – through its debugging tools – lets you see the entire state of your application’s stores any point an action is fired, inside a singular immutable map. Stores hold immutable data, and each time an action is fired, data is changed, which results in the creation of an entirely new immutable map.
Luckily, this process of generating an entirely new map each time an action fires is extremely efficient.
Benefit: By adopting immutability, we have been able to debug our application in much greater detail, since we are able to see exactly what the state of our application is at every user interaction.
Finally, I wanted to touch on Modules. Modules are an organizational concept that groups up actions, getters, and stores that perform a common set of functionality.
In other Flux implementations I’ve used, I’ve actually missed not having something like this. I always felt I was creating a bunch of stores, writing a bunch of actions, and then “gluing” everything together. In NuclearJS, Modules are the “glue”, and they are built in to the framework.
A module is required by a React Component, and is the way a component can call specific actions or getters (here’s an example of that).
Benefit: Modules provide the “glue” in combining relevant getters, actions, and stores. They can then be required by individual components. Multiple components can require the same module. Conversely, if you see yourself using the same store/getters/actions in multiple “modules”, you may want to move it to a “Common” module. Code re-usability FTW.
I hope this article helps explain some of the novel concepts behind NuclearJS. Architectural concepts are often hard to explain in words, and I learned it by just digging into the code. The awesome team at Optimizely now has a nice landing page for NuclearJS, so definitely check that out.
Also, read this short section on NuclearJS’s Readme that explains how it is different from other Flux implementations.
I considered creating something like a To-do List app using NuclearJS (I may still do it), but you really start seeing the pros of NuclearJS as your codebase grows and becomes more complex (dozens of stores, actions, getters, and modules).
Suffice to say, we have been very happy with NuclearJS at SoundHound. We have used it to build Houndify.com, which is our developer-facing website that allows you to provision an application and get access to the Houndify SDK.
If you have any questions, or have any suggestions on things that I can explain better, please leave a comment below! If you’re a front-end engineer who is interested in NodeJS, React, and working on the bleeding-edge, send me a message and we’ll chat.