Flux Dispatcher: Under the Hood

With the React library currently taking the spotlight, there is a lot of discussion surrounding the different flavors of Flux architecture. There are some who say that with the increasing popularity of Dan Abramov's Redux (which actually does away with the dispatcher in favor of a more functional approach using reducers), dispatchers are now a vestiage that are no longer needed. Whether or not that is true, the dispatcher centric architecture is still an interesting solution to managing the data flow through the client and is worth understanding.

In this post, I'm assuming that you have a basic understanding of how Flux works, but perhaps are a little confused about what how the dispatcher actually dispatches. If you don't know anything about Flux I recommend checking out a Cartoon guide to Flux written by Lin Clark.

What is the Dispatcher?

The dispatcher is the binding piece of logic that sits at the center of the original Flux architecture and brings all of the elements together. When broken down to its most essential parts, the dipatcher has two main functions.

  • It registers listeners, which are functions that are registered by the stores of your application. Each store will have its own listener, and that listener will examine the payloads as they come in to see if it is something that is relevant to them.
  • It dispatches payloads, by passing them to all of the registered listeners. Payloads are essentially the data/actions that you are sending to the stores.

While a fully implemented dispatcher has a bit more functionality than just registering and dispatching (e.g. unregister, waitFor), we can usually do without those methods for simple applications and will leave them out of the scope of this post.

A dispatcher registers listeners and then sends events (payloads) to those listeners at the appropriate time through action creators. When we register listeners, we can either store them in an array or an object. In the example below, we will be storing the listeners in an object and setting the key to be a unique identifier which is generated by a uniqueIdGenerator function.

The reason for using a unique ID generator is that when we do want to add in additional dispatcher funtionality (like unregister or waitFor), we need to be able to call upon specific listeners. However, just know that for the example below, it is unnecessary and we could have used an array just as easily.

// dispatcher.js

function uniqueIdGenerator() {/*...*/};

var listeners = {};

module.exports = {
    register: function (callback) {
        var id = uniqueIdGenerator();
        listeners[id] = callback;
        return id;
    },
    dispatch: function (payload) {
        for (var id in listeners) {
            var listener = listeners[id];
            listener(payload);
        }
    }
};

So when we look at the code for a bare bones dispatcher, we can actually see that it is pretty simple.

  • We can see that the listener function is passed in to the register method where it is added to the listener object with the key being a unique ID.

  • The dispatcher, when passed a payload, will loop through all of the registered listeners and will invoke each of them with the payload.

That's all there is to it!

If you want to look at the actual code for the Facebook Flux Dispatcher you can see that it is not that much more complicated.

So how does the dispatcher fit in with the rest of Flux?

As mentioned, the register method is invoked in each store of the application so that the stores can each have a listener that will be able to examine the payloads that are sent out by action creators. The stores in Flux are the components that hold the single source of truth of the application. The main rule with stores is that only the stores can change their own state. This makes it easy to identify and fix any unexpected behaviors that may occur.

On the other side, we have action creators which are responsible for dispatching payloads. Generally the payloads will be an object that not only contain the data, but also will have a type property that the listeners will check (sometimes with a switch statement) to see if the payload is relevant to their related store.

Remember that when a payload is dispatched, it is sent to all of the listeners. Once the listeners verify the payload, they will use the data inside to invoke functions in the store which will change the state of the store. Finally our stores will trigger an event telling the component views to render an updated UI based on the state change.

That is basically all you really need to know to understand how the dispatcher functions and how it fits into the complete system. Let me know you have any questions in the comments.