Simple Data Flow in React Apps Using Flux and Backbone: A Tutorial with Examples

React.js is a fantastic library. Sometimes it seems like the best thing since sliced Python. React is only one part of a front-end application stack, however. It doesn’t have much to offer when it comes to managing data and state.

Facebook, the makers of React, have offered some guidance there in the form of Flux. Flux is an “Application Architecture” (not a framework) built around one-way data flow using React Views, an Action Dispatcher, and Stores. The Flux pattern solves some major problems by embodying important principles of event control, which make React applications much easier to reason about, develop, and maintain.

Here, I’ll introduce basic Flux examples of control flow, discuss what’s missing for Stores, and how to use Backbone Models and Collections to fill the gap in a “Flux-compliant” way.

(Note: I use CoffeeScript in my examples for convenience and brevity. Non-CoffeeScript developers should be able to follow along, and can treat the examples as pseudocode.)

Introduction to Facebook’s Flux

Backbone is an excellent and well-vetted little library that includes Views, Models, Collections, and Routes. It’s a de facto standard library for structured front-end applications, and it’s been paired with React apps since the latter was introduced in 2013. Most examples of React outside of Facebook.com so far have have included mentions of Backbone being used in tandem.

Unfortunately, leaning on Backbone alone to handle the entire application flow outside of React’s Views presents unfortunate complications. When I first began working on React-Backbone application code, the “complex event chains” that I had read about didn’t take long to rear their hydra-like heads. Sending events from the UI to the Models, and then from one Model to another and then back again, makes it hard to keep track of who was changing who, in what order, and why.

This Flux tutorial will demonstrats how the Flux pattern handles these problems with impressive ease and simplicity.

An Overview

Flux’s slogan is “unidirectional data flow”. Here’s a handy diagram from the Flux docs showing what that flow looks like:

The important bit is that stuff flows from React --> Dispatcher --> Stores --> React.

Let’s look at what each of the main components are and how they connect:

The docs also offer this important caveat:

Flux is more of a pattern than a framework, and does not have any hard dependencies. However, we often use EventEmitter as a basis for Stores and React for our Views. The one piece of Flux not readily available elsewhere is the Dispatcher. This module is available here to complete your Flux toolbox.

So Flux has three components:

Views (React = require('react'))

Dispatcher (Dispatcher = require('flux').Dispatcher)

Stores (EventEmitter = require('events').EventEmitter)

(or, as we’ll soon see, Backbone = require('backbone'))

The Views

I won’t describe React here, since so much has been written about it, other than to say that I vastly prefer it to Angular. I almost never feel confused when writing React code, unlike Angular, but of course, opinions will vary.

The Dispatcher

The Flux Dispatcher is a single place where all events that modify your Stores are handled. To use it, you have each Store register a single callback to handle all events. Then, whenever you want to modify a Store, you dispatch an event.

Like React, the Dispatcher strikes me as a good idea, implemented well. As an example, an app that allows the user to add items to a to-do list might include the following:

In practice, I was shocked to see how much cleaner my code was when using the Dispatcher to modify my Stores, even without using waitFor.

The Stores

So data flows into Stores through the Dispatcher. Got it. But how does data flow from the Stores to the Views (i.e., React)? As stated in the Flux docs:

[The] view listens for events that are broadcast by the stores that it depends on.

Okay, great. Just like we registered callbacks with our Stores, we register callbacks with our Views (which are React Components). We tell React to re-render whenever a change occurs in the Store which was passed in through its props.

The Missing Piece

By telling you to use raw EventEmitter, Flux is recommending that you recreate maybe 50-75% of Backbone’s Models & Collections every time you create a Store. Using EventEmitter for your stores is like using bare Node.js for your server when well-built microframeworks like Express.js or equivalent already exist to take care of all the basics and boilerplate.

Just like Express.js is built on Node.js, Backbone’s Models and Collections are built on EventEmitter. And it has all the stuff you pretty much always need: Backbone emits change events and has query methods, getters and setters and everything. Plus, Backbone’s Jeremy Ashkenas and his army of 230 contributors did a much better job on all of those things than I am likely to be able to do.

I have applied this Flux and Backbone approach to my own projects, and once I re-architected my React application to use this pattern, almost all the ugly bits disappeared. It was a little miraculous: one by one, the pieces of code that had me gnashing my teeth looking for a better way were replaced by sensible flow. And the smoothness with which Backbone seems to integrate in this pattern is remarkable: I don’t feel like I’m fighting Backbone, Flux, or React in order to fit them together in a single application.

Example Mixin

Writing the this.on(...) and this.off(...) code every time you add a FluxBone Store to a component can get a bit old.

Here’s an example React Mixin that, while extremely naive, would certainly make iterating quickly even easier:

Syncing with a Web API

In the original Flux diagram, you interact with the Web API through ActionCreators only, which require a response from the server before sending actions to the Dispatcher. That never sat right with me; shouldn’t the Store be the first to know about changes, before the server?

I choose to flip that part of the diagram around: the Stores interact directly with a RESTful CRUD API through Backbone’s sync(). This is wonderfully convenient, at least if you’re working with an actual RESTful CRUD API.

Data integrity is maintained with no problem. When you .set() a new property, the change event triggers a React re-render, optimistically displaying the new data. When you try to .save() it to the server, the request event lets you know to display a loading icon. When things go through, the sync event lets you know to remove the loading icon, or the error event lets you know to turn things red. You can see inspiration here.

There’s also validation (and a corresponding invalid event) for a first layer of defense, and a .fetch() method to pull new information from the server.

For less standard tasks, interacting via ActionCreators may make more sense. I suspect Facebook doesn’t do much “mere CRUD”, in which case it’s not surprising they don’t put Stores first.

Conclusion

The Engineering teams at Facebook have done remarkable work to push the front-end web forward with React, and the introduction of Flux gives a peek into a broader architecture that truly scales: not just in terms of technology, but engineering as well. Clever and careful use of Backbone (per this tutorial’s example) can fill the gaps in Flux, making it amazingly easy for anyone from one-person indie shops to large companies to create and maintain impressive applications.

About the author

Alex is an entrepreneur and recent Wharton grad who recently closed a startup and is contracting while he travels. He has built over 10,000 LOC projects from the ground up. He takes great pride in developing absurdly simple user interfaces on architecture that scales. [click to continue...]

Comments

leogcrespo

Hey! Nice writeup! I'm also exporing a little bit this patter, but yet haven't concluded anything I like 100%. Yet this blog post is really helpful to keep thinking. Would really like to chat with you and discuss about opinions about this!
Now, regarding the FluxBoneMixin code, I don't think the unmount code is actually cleaning up correctly, since you're calling `off` with a different function instance (which happens to contain the same body, but that's all).
You could directly bind and unbind the @forceUpdate method, like this:
@props[propName].on "all", @forceUpdate
@props[propName].off "all", @forceUpdate
And things will work as expected, since you're using the same function instance. As a bonus, you don't need to use the context parameter, since the forceUpdate function is auto bound to the component.

mark

That's a good point. In the current example, a new function is created for off.
But what will be the function context if it's bound like this?
@props[propName].on "all", @forceUpdate
Will `this` still be correct?

leogcrespo

Yes, because React already does the auto binding on all the component's methods

maxime

I want to give a try to your architecture. Can you give a link with the GitHub/sources of the project, please?

will62

Why are you manually changing props and then calling forceUpdate() instead of setting state?
Otherwise, seems like a very cool way to leverage what backbone already does pretty well.

Okay, that mangled my white space, but I think you should still be able to follow it.

Alex Rattray

Flux certainly isn't necessary, but I found things got messier without it. Updating your models directly from your view code (React) is certainly easier, but it's also less maintainable since the code that updates models is fractured out across many different components.

Alex Rattray

Great question! Modifying the Backbone models directly lets you <code>.save()</code> them to the server, ensuring that what the server knows and what the client knows are as close to the same thing as possible. `setState` can be dangerous because things can get a bit out of sync if you're not super careful.
That said, another pattern similar to the one I describe would be to call `@setState(@props.model.changedAttributes())` in the `change` handler. It may work better depending on your circumstances, but it requires more babysitting since you won't have access to any other Backbone properties. Reading directly from the Store is more reliable, and less work. And there should not be any performance hit to using `@forceUpdate` compared to `@setState()`, as long as you are using it appropriately.

Alex Rattray

No worries! Still perfectly readable. For future reference, you can wrap code in &lt;code&gt; and &lt;pre&gt; blocks for syntax highlighting in disqus. Not as convenient as backticks (`) but it does the job.
Ref: https://help.disqus.com/customer/portal/articles/665057-syntax-highlighting

Alex Rattray

Unfortunately, this doesn't work. React throws the error:
<pre><code>
Uncaught Error: Invariant Violation: enqueueUpdate(...): You called `setProps`, `replaceProps`, `setState`, `replaceState`, or `forceUpdate` with a callback that isn't callable.
</code></pre>
Although mark is correct that I'm not doing <code>off</code> correctly here. I hope to update the article in the near future, but for now, here is a gist in which this is done more completely: https://gist.github.com/rattrayalex/5617976719f7d8ead154

Alex Rattray

I'm not super happy with all aspects at this point, but here is one app where I have used this architecture: https://github.com/rattrayalex/splashreader
The entry point is coffee/app.coffee

leogcrespo

Hah! Seems forceUpdate can receive an optional callback parameter which is what is messing this because the events parameters are being passed into the function. Your gist definitely solves that problem

Vyacheslav

I'm using React and backbone too. I'm familiar with Flux, but I can't see why modifying store directly (via set method) is a bad idea. I'm using ReactBackbone Mixin and also I use mostly events triggered after modifying model. So, you modify in React Component model, then model throws an event, and then all the subscribers who depend on this model via ReactBackbone update their view.

deBrice

I like the integration of backbone but I don't think it should live on the store itself. I might be wrong, but I believe backbone should live in the `Web API Utils` module, triggering actions registered in the `Action Creator` which will then go through the dispatcher. You're implementation would prevent the dispatcher from notifying all the store of a "serverAction" incoming data.

Alex Rattray

@disqus_vg4gQjd0ym:disqus , Backbone could certainly also be used in <code>Web API Utils</code>, for example, when using React with Immutables, another interesting idea.
In this case, Backbone itself emits events when new information comes from the server. So if a collection receives a new model from the server, for example, it will emit the <code>"add"</code> event, which can be listened to by the UI or other Stores. That aspect is pretty much in keeping with Flux dogma. Using Backbone for your stores means your data is always the exact same, everywhere; you never have to worry about your Web API Utils being a little different from what's going into your UI.

Alex Rattray

That works too -- it's what most people did before Flux came about, as far as I'm aware. The problem has to do not with the writing but the maintaining; it can be harder to figure out where modifications are coming in from when you're unfamiliar with the codebase. For more, see this post: http://www.code-experience.com/avoiding-event-chains-in-single-page-applications/

deBrice

I see some major flows in your implementation (backbone as a store).
First your stores now have setters. If you work in a team, you now have to make sure nobody will use them which would break the Flux design pattern (unidirection).
Your store will now have to listen to other stores event, not the dispatcher anymore. Remember that the dispatcher, being a bottleneck by design, simplify your overall data flow by registering all your store in one place
If you wanted to use the dispatcher, your store would now have to call actions (which in turn would call the dispatcher)... you are now be in a risky position as infinite loop wont be detected by your dispatcher anymore (which is a key feature of flux).
Don't get me wrong, I understand your argument that having backbone in the store makes you write less code and I understand it works work for you. But the purpose of flux is not to write less code but being a sustainable design pattern as your software grows by asserting a set of rules like: Store can only be touched/set by the dispatcher they registered to.
Finally, stores are warehouse for a domain, not an object storage. Look at the logic behind the UnreadThreadStore https://github.com/facebook/flux/blob/master/examples/flux-chat/js/stores/UnreadThreadStore.js , in the Model world, this would be a function (`where read is false`) on the Backbone ThreadCollection but in react the domain prevail.

dan

According to coffeescript best practices, if `this` is used by itself, we use `this` instead of a lonely `@` symbol.

Filip Dupanović

@disqus_vg4gQjd0ym:disqus if your using a collection as a store already, that means you've resorted to having a store imbued with knowing that it's data is persisted elsewhere. What your suggesting is yanking this out of the store, extracting it into a generic component, spilling the beans on what the external endpoints for syncing the store are outside it's boundaries and going back to a completely uninteresting data store, making the author's proposed Fluxbone solution even more so.
I don't see why, thence, the store, being that it's already registered with the dispatcher, couldn't handle the `FETCH_DATA` action and create additional `FETCH_SUCCESS`, `FETCH_ERROR` actions from the response and handle those in return as well as soon as they're dispatched back to it to reset or flush it's list of models. This is fully within the capabilities of `Backbone.Collection.fetch` to perform, see `options.success`, `options.error`, `options.parse`: https://github.com/jashkenas/backbone/blob/1.2.0/backbone.js#L566

deBrice

Separation of concern is important. I can't explain more and I'm not willing to get into a troll war.

Filip Dupanović

I've no intention to troll, but your completely misleading the audience. It is perfectly acceptable for stores to initiate XHR requests and register response callbacks with the dispatcher to reciprocally update itself with the payload provided in the actions that will ensue. There is no circular race with dispatching and handling actions for asynchronous events, there are no infinite loops with a fixed sequence of events and the resulting state mutation on the store still happen "in response" to an action.
It is furthermore completely redundant to extract `Backbone.sync`behavior from a `Backbone.Collection` and delegate it to a new controller-like type. The point is that your trying to use Backbone here, not to zealously follow any concrete Flux implementation which doesn't.

deBrice

Stores that trigger actions aren't flux pattern but something else.

deBrice

Having a store agnostic to data source allow more flexibility. You can have a given action triggered by a socket, an XHR request in some other case, a fixture when testing, an initial setup (constants)... If you start designing large software you'll see parts of your application evolving with time. Having simple component and a good separation of concern would allow you to maintain an app without going through a full refactor.
If you never had to manage large software with a long life expectancy and a large team of developers you wont understand how critical is the ability to maintain isolated parts.

Alex Mills

is it ready yet? :)

Alex Mills

coffeescript itself will be a lonely nothing symbol godwilling

Wengi Vragen

If I plan to use ReactJS with GraphQL/Relay, is there still a benefit to using Backbone with ReactJS?

Einar Paul Qvale

Would you still recommend this pattern? Things are evolving quickly in the React space, and Redux seems to be emerging as a favourite. We use Backbone in the app we're building now, and we're not going to remove it since there's too much code to refactor, so I'm looking for a recommended approach for integrating React with Backbone (and a lot of people seem to think this is a bad idea these days, mostly due to the mutability of Backbone models I guess).
Integrating React and Backbone can of course easily be done simply by modifying and listening to models from the React views themselves, but as you say this might become hard to debug and maintain after a while (although I don't feel this has become a problem with our Backbone views, which more or less do the same).
Redux looks good though, so I would probably prefer to find a way to integrate that with what we have today, rather than Flux. Just not sure about a single global state-tree for our entire app, it contains a rather large amount of data, and it's less feasible considering all the Backbone views and models we already have.

Alex Rattray

While I can't comment as to your specific use-case, I would agree that Redux has really taken off since this article has been written, and it's what I generally recommend these days instead of the approach detailed in this piece.

Alex is an entrepreneur and recent Wharton grad who recently closed a startup and is contracting while he travels. He has built over 10,000 LOC projects from the ground up. He takes great pride in developing absurdly simple user interfaces on architecture that scales.