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

View all articles

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:

Facebook Flux uses an “unidirectional data flow” model that varies a little when paired with React and Backbone.

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:

  1. Views (React = require('react'))
  2. Dispatcher (Dispatcher = require('flux').Dispatcher)
  3. 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 TodoDispatcher.coffee
Dispatcher = require("flux").Dispatcher

TodoDispatcher = new Dispatcher() # That's all it takes!.

module.exports = TodoDispatcher    
# in TodoStore.coffee
TodoDispatcher = require("./TodoDispatcher")

TodoStore = {items: []}

TodoStore.dispatchCallback = (payload) ->
  switch payload.actionType
    when "add-item"
      TodoStore.items.push payload.item
    when "delete-last-item"
      TodoStore.items.pop()

TodoStore.dispatchToken = TodoDispatcher.registerCallback(TodoStore.dispatchCallback)

module.exports = TodoStore
# in ItemAddComponent.coffee
TodoDispatcher = require("./TodoDispatcher")

ItemAddComponent = React.createClass
  handleAddItem: ->
    # note: you're NOT just pushing directly to the store!
    # (the restriction of moving through the dispatcher
    # makes everything much more modular and maintainable)
    TodoDispatcher.dispatch
      actionType: "add-item"
      item: "hello world"

  render: ->
    React.DOM.button {
      onClick: @handleAddItem
    },
      "Add an Item!"

This makes it really easy to answer two questions:

  1. Q: What are all the events that modify MyStore?
    • A: Just check the cases in the switch statement in MyStore.dispatchCallback.
  2. Q: What are all possible sources of that event?
    • A: Simply search for that actionType.

This is much easier than, for example, looking for MyModel.set and MyModel.save and MyCollection.add etc, where tracking down the answers to these basic questions gets really hard really fast.

The Dispatcher also allows you to have callbacks run sequentially in a simple, synchronous fashion, using waitFor. For example:

# in MessageStore.coffee
MyDispatcher = require("./MyDispatcher")
TodoStore = require("./TodoStore")

MessageStore = {items: []}

MessageStore.dispatchCallback = (payload) ->
  switch payload.actionType
    when "add-item"
      # synchronous event flow!
      MyDispatcher.waitFor [TodoStore.dispatchToken]

      MessageStore.items.push "You added an item! It was: " + payload.item

module.exports = MessageStore

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.

For example:

# in TodoListComponent.coffee
React = require("react")

TodoListComponent = React.createClass
  componentDidMount: ->
    @props.TodoStore.addEventListener "change", =>
      @forceUpdate()
    , @

  componentWillUnmount: ->
    # remove the callback

  render: ->
    # show the items in a list.
    React.DOM.ul {}, @props.TodoStore.items.map (item) ->
      React.DOM.li {}, item

Awesome!

So how do we emit that "change" event? Well, Flux recommends using EventEmitter. From an official example:

var MessageStore = merge(EventEmitter.prototype, {

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  /**
   * @param {function} callback
   */
  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },

  get: function(id) {
    return _messages[id];
  },

  getAll: function() {
    return _messages;
  },
// etc...

Gross! I have to write all that myself, every time I want a simple Store? Which I’m supposed to use every time I have a piece of information I want to display? There has to be a better way!

The Missing Piece

Backbone’s Models and Collections already have everything Flux’s EventEmitter-based Stores seem to be doing.

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.

As an example for this Backbone tutorial, I converted the MessageStore example from above to a Backbone version.

It’s objectively less code (no need to duplicate work) and is subjectively more clear and concise (for example, this.add(message) instead of _messages[message.id] = message).

So let’s use Backbone for Stores!

The FluxBone Pattern: Flux Stores by Backbone

This tutorial is the basis of an approach I have proudly dubbed FluxBone, the Flux architecture using Backbone for Stores. Here is the basic pattern of a FluxBone architecture:

  1. Stores are instantiated Backbone Models or Collections, which have registered a callback with the Dispatcher. Typically, this means they are singletons.
  2. View components never directly modify Stores (for example, no .set()). Instead, components dispatch Actions to the Dispatcher.
  3. View components query Stores and bind to their events to trigger updates.

This Backbone tutorial is designed to look at the way Backbone and Flux work together in React applications.

Let’s use Backbone and Flux examples to look at each piece of that in turn:

1. Stores are instantiated Backbone Models or Collections, which have registered a callback with the Dispatcher.

# in TodoDispatcher.coffee
Dispatcher = require("flux").Dispatcher

TodoDispatcher = new Dispatcher() # That's all it takes!

module.exports = TodoDispatcher
# in stores/TodoStore.coffee
Backbone = require("backbone")
TodoDispatcher = require("../dispatcher")

TodoItem = Backbone.Model.extend({})

TodoCollection = Backbone.Collection.extend
  model: TodoItem
  url: "/todo"

  # we register a callback with the Dispatcher on init.
  initialize: ->
    @dispatchToken = TodoDispatcher.register(@dispatchCallback)

  dispatchCallback: (payload) =>
    switch payload.actionType
      # remove the Model instance from the Store.
      when "todo-delete"
        @remove payload.todo
      when "todo-add"
        @add payload.todo
      when "todo-update"
        # do stuff...
        @add payload.todo,
          merge: true
      # ... etc


# the Store is an instantiated Collection; a singleton.
TodoStore = new TodoCollection()
module.exports = TodoStore

2. Components never directly modify Stores (for example, no .set()). Instead, components dispatch Actions to the Dispatcher.

# components/TodoComponent.coffee
React = require("react")

TodoListComponent = React.createClass
  handleTodoDelete: ->
    # instead of removing the todo from the TodoStore directly,
    # we use the Dispatcher
    TodoDispatcher.dispatch
      actionType: "todo-delete"
      todo: @props.todoItem
  # ... (see below) ...

module.exports = TodoListComponent

3. Components query Stores and bind to their events to trigger updates.

# components/TodoComponent.coffee
React = require("react")

TodoListComponent = React.createClass
  handleTodoDelete: ->
    # instead of removing the todo from the TodoStore directly,
    # we use the dispatcher. #flux
    TodoDispatcher.dispatch
      actionType: "todo-delete"
      todo: @props.todoItem
  # ...
  componentDidMount: ->
    # the Component binds to the Store's events
    @props.TodoStore.on "add remove reset", =>
      @forceUpdate()
    , @
  componentWillUnmount: ->
    # turn off all events and callbacks that have this context
    @props.TodoStore.off null, null, this
  render: ->
    React.DOM.ul {},
      @props.TodoStore.items.map (todoItem) ->
        # TODO: TodoItemComponent, which would bind to
        # `this.props.todoItem.on('change')`
        TodoItemComponent {
          todoItem: todoItem
        }

module.exports = TodoListComponent

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:

# in FluxBoneMixin.coffee
module.exports = (propName) ->
  componentDidMount: ->
    @props[propName].on "all", =>
      @forceUpdate()
    , @

  componentWillUnmount: ->
    @props[propName].off "all", =>
      @forceUpdate()
    , @
# in HelloComponent.coffee
React = require("react")

UserStore = require("./stores/UserStore")
TodoStore = require("./stores/TodoStore")

FluxBoneMixin = require("./FluxBoneMixin")


MyComponent = React.createClass
  mixins: [
    FluxBoneMixin("UserStore"),
    FluxBoneMixin("TodoStore"),
  ]
  render: ->
    React.DOM.div {},
      "Hello, #{ @props.UserStore.get('name') },
      you have #{ @props.TodoStore.length }
      things to do."

React.renderComponent(
  MyComponent {
    UserStore: UserStore
    TodoStore: TodoStore
  }
  , document.body.querySelector(".main")
)

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 Rattray, United States
member since May 8, 2014
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...]
Hiring? Meet the Top 10 Freelance Front-End Developers for Hire in December 2016

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.
Keith Grant
Since you've got Backbone already loaded, you may not need Flux; just use Backbone.Events as your Dispatcher. I've used this pattern, and it's really simple: MyComponent = React.createClass mixins: [Backbone.Events] componentDidMount: -> @on 'event:name', @handleEvent handleEvent: -> @setState eventTriggered: true render: -> <ChildComponent dispatch={@trigger}> </ChildComponent> and then in the ChildComponent, to dispatch an event, just call @props.dispatch('event:name', payload)
Keith Grant
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.
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Alex Rattray
Python Developer
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.