The 2 Fundamental Laws of Flux, and the Functional Reactive Flux

Everyone has a proverbial large single page app to be created. And under those conditions, it seems like nothing else will allow for the maintainability and consistency than Flux. Here, I introduce a Flux implementation that uses Reactive principles: the Functional Reactive Flux.

When DO I Need Flux?

According to Pete Hunt, one of the original authors of React, the use of Flux should be reserved for an app when the following two conditions are met. I’m going to call it the Two Fundamental Laws of Flux.

I think the use of flux is justified when two conditions are met:
1. You have a piece of data that needs to be used in multiple places in your app, and passing it via props makes your components break the single-responsibility principle (i.e. makes their interface make less sense)
2. There are multiple independent actors (generally, the server and the end-user) that may mutate that data.
Stores solve the first problem (as do single state atoms and event emitters), a serializable action queue solves the second.

In other words, you do NOT have a Flux implementation unless these two issues are addressed. Now, I am not entirely in agreement that the given solutions are required for Flux — as you’ll read my reasoning below.

Law 1: Shared State

Now, let’s all remember when we all first heard about React. We probably watched a video or two from React Conf’s of yore about Flux as well. It was famously shown in the Facebook chat count demo that a central chat count store should be used to keep two UI’s in sync. So, we arrive at the first idea of Flux architecture: the store (or, the Repository Pattern).

Since Flux has been out, there had been many variations of this. Battles have been fought, and we can safely say that Redux has pretty much won the Flux implementation war. So, let’s look at Flux through the lens of Redux to give us substance. Redux has a single state tree for the store. This is very simple in principle, especially if you have the ability to build this tree to arbitrary complexity via root splitting when your app grows.

Redux restricts the manipulation of the store through reducers. These reducers take the current state and an action payload as input to produce a new slightly modified copy of the old state (introducing the immutable store), and then triggering a change notification to all components. Through the use of some clever immutable libraries, you can get the reducers to look almost Javascript-like. On a modest sized team and project, this style of programming shines. However, I have yet to hear about a large team of developers (20+) using Redux to build something large (>100k lines of code). Please tweet me (@kenneth_chau) if you have seen this in the wild somewhere!

My view is that the design of the state tree is hard. It almost reminds me of a waterfall development methodology where you have plan all the details ahead. Adjustments of the state tree brings with it non-trivial refactoring of the combineReducers(). Quite often, if you have a complex application dealing with multiple domains, your actions affect multiple points in the store (thus multiple parts of the tree). In that likely scenario, refactoring the shape of the tree to adjust for new requirement is a difficult task with reducers.

Another issue with Redux is that the Javascript language has poor support for immutable data structures, and the existing libraries (however clever) simply do not fill in the gap completely. Again, on a large team, this would truly affect productivity when the slightest mutation of the state inside a reducer becomes a rather subtle bug which is hard to find.

Pete’s First Fundamental Law of Flux requires a shared state. However, it does not necessarily mean an immutable store. Redux came up with this idea by observing other frameworks written in other functional languages that have excellent support for immutable data structures. If we choose to stay around the Javascript / Typescript / Babel / ES2015 camp, then we should pursue something more natural to this language.

Law 2: Coordination of Data Manipulation

Pete’s Second Fundamental Law of Flux requires the implementation of Flux to include some sort of coordination of serialized actions impacting the store. So, whereas the 1st law deals with the reading, the 2nd deals with the writing. Notice that those are well separated creating a unidirectional data flow.

Honestly, the Flux pattern still holds if there were no dispatchers. The action queue is merely an implementation detail. From the Java and C# camp, we have been doing this all along with message queues. This is no different. There is no magic behind the dispatcher at all — one can use any method to make sure the changes to the store happen through a single mechanism.

If all of your application’s action triggers happen on the browser, then there is no need for a dispatcher. Given this, all you need to guarantee unidirectional flow is a convention that the store can only be modified by a set of exported action functions. No dispatcher needed.

Of course, things can get out of hand when you have to coordinate actions between many actors (server push, client events, legacy code, etc.). The message queue is a good way to abstract messages from the actions. This is the how Facebook keeps your unread message count in-sync now.

Look at Facebook’s dispatcher.js and ask, why do you truly need another library on top of that one function? Answer: boilerplate. Redux is supposed to be a library to reduce boilerplate. TL;DR: Redux didn’t really get rid of the vanilla Flux boilerplate. It merely refined the concept of the store and the manipulation of it all. I find it a bit jarring that it takes a whole page by the author to argue that the boilerplate is by design.

The Functional Reactive Flux

You might be wondering now that I’ve spent this long bashing the existing, most popular Flux framework, what would we use instead? I recommend the approach of a reactive store and reactive components. Look no further than Michel Weststrate’s truly remarkable mobservable library. There, you’ll find the fundamentals of a Javascript-friendly library based on the idea of transparent functional reactive programming.

Functional reactive programming (FRP) is a powerful way to represent behaviors that applications should have in terms of event streams. Take a look at Angular 2’s approach to their HTTP Provider with Rx.js Observable and you’ll see the power (debounce, throttle, retry in just a few lines of code).

Such ReactiveX goodness can be achieved easily thanks to React’s game-loop render idea and mobservable’s run-time discovery of dependencies on component render. You see, mobservable will keep track of an observer’s dependent observables — and if any of the observables changed, then it would notify the observer. If the observer happens to be a React component’s render function, then you have just made a reactive React component.

Some examples to show mobservable’s simple syntax. I love Typescript, so that’s what I’ll use here. (examples taken from mobservable’s documentation):

First, the Store:

import {observable} from 'mobservable';
class TodoStoreClass {
@observable todos = [{
title: 'Find a clean mug',
completed: true
}]

@observable get completedCount() {
return this.todos.filter((todo) => todo.completed).length;
}
    addTodo(item) {
this.todos.push(item);
}
}
let TodoStore = new TodoStoreClass();
export {TodoStore};

Next, the View:

import {observer} from 'mobservable-react';
import {TodoStore} from './todostore';
@observer 
class MyComponent extends React.Component {
render() {
return <button onClick={this.onButtonClick}>Add</button>
}

onButtonClick = (e) => {
TodoStore.addTodo({title: 'added', completed: false});
}
}

Do you see an action queue there? No. But what you DO see is now that the view is reactive. There is one defined convention for callers to add to-do items via addTodo().

Want a single state tree, like Redux? Sure! You can even make your mutations actually be inside a transaction in one go:

import {observable, transaction} from ‘mobservable’;
export default class ReactiveStore<T> {
private state: T = <T>observable({});
    // Call it 'update', 'dispatch', or whatever you want
mutate(action: Action): void {
transaction(() => { action(state); });
}
}

If you really need a real queue, then turn those actions into messages and have a proper dispatcher that can handle it. I leave that as an exercise for the reader!

For further reading, check out this excellent post by mobservable’s author. Bonus: Michel actually uses it in his day time job, so it is definitely in production right now. Check out the scale of his app:

Conclusion

I agree with Michel. I don’t dare to say how many reducers and selectors a healthy sized application would have required. I maintain a Web app that is of significant lines of code (above Michel’s example, above), I cannot even begin to comprehend the number of domains the application entails. mobservable is up to the task of handling keeping track of the dependencies at scale, and I’m confident that you’ll have a much easier time developing your application and optimizing your application’s performance with this than trying to figure how to avoid rendering with “shouldComponentUpdate()” by hand.

Show your support

Clapping shows how much you appreciated Ken’s story.