The Flux Quick Start Guide

Feb 26, 2015

This article will give you an overview of how to build JavaScript applications with the Flux pattern. It’s the minimal amount of material to get you familiar with the core Flux concepts. You should follow along with the accompanying starter kit. You’ll need a basic understanding of React and preferably some experience building components. Read the The React Quick Start Guide if you’re unfamiliar with React.


Concepts

Flux is an architectural pattern for implementing user interfaces. It has three primary concepts; Views, Stores and the Dispatcher. There are also several secondary concepts; Actions, Action Types, Action Creators and Web Utils.

Take your time reading the following definitions then follow the tutorial. Read the definitions again and you’ll be able to start using the Flux pattern in your own applications.

Primary Concepts

Views are React components. They’re responsible for rendering interfaces and handling user events. Their data is obtained from the Stores.

Stores manage data. A single Store manages data for a single domain. When a Store changes its data, it notifies the Views.

The Dispatcher receives new data and passes it to the Stores. Stores update their data (when applicable) and inform the Views.

Secondary Concepts

Actions are the objects passed to the Dispatcher. They contain the new data and an Action Type.

Action Types are the Actions which the system can create. Stores only update their data when Actions with particular Action Types occur.

Action Creators are the objects which build Actions and send them to the Dispatcher or Web Utils.

Web Utils are objects for communicating with external API’s. For example, an Action Creator may invoke requesting new data from the server.


There’s quite a lot to absorb at once. I highly suggest following along with the the starter kit and typing out each line to achieve the best comprehension.

Disclaimer: Use of constants and Web Utils is omitted. This makes understanding Flux simpler and once you’ve grokked the pattern reading the official examples will fill in these secondary concepts.

Views

After getting the starter kit setup (instructions are in the repository) you’ll find the following app.js file in the src directory.

var React = require('react');
var Comments = require('./views/comments');
var CommentForm = require('./views/comment-form');

var App = React.createClass({

  render: function() {
    return (
      <div>
        <Comments />
        <CommentForm />
      </div>
    );
  }
});

React.render(<App />, document.getElementById('app'));

This renders our Views to the DOM. Ignore the Comments View and focus on implementing the CommentForm .

var React = require('react');

var CommentActionCreators = require('../actions/comment-action-creators');

var CommentForm = React.createClass({

  onSubmit: function(e) {
    var textNode = this.refs.text.getDOMNode();
    var text = textNode.value;

    textNode.value = '';

    CommentActionCreators.createComment({
      text: text
    });
  },

  render: function() {
    return (
      <div className='comment-form'>
        <textarea ref='text' />
        <button onClick={this.onSubmit}>Submit</button>
      </div>
    );
  }
});

module.exports = CommentForm;

The CommentForm requires a CommentActionCreators object which is (as the name suggests) an Action Creator.

On form submission the createComment function is passed a comment object constructed from the textarea’s value. Let’s build this Action Creator to accept the comment.


Actions

Under the actions directory create and implement the following comment-action-creators.js file.

var AppDispatcher = require('../dispatcher/app-dispatcher');

module.exports = {

  createComment: function(comment) {
    var action = {
      actionType: "CREATE_COMMENT",
      comment: comment
    };

    AppDispatcher.dispatch(action);
  }
};

The createComment function builds an Action which contains an Action Type and comment data. This Action is passed to the Dispatcher’s dispatch function.

Let’s build the Dispatcher to accept Actions.

Note: We could write this code in the View - communicating with the Dispatcher directly. However, it’s best practice to use an Action Creator. It decouples our concerns and provides a single interface for the Dispatcher.


Dispatcher

Under the dispatcher directory, create and implement the following app-dispatcher.js file.

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

module.exports = new Dispatcher();

A single Dispatcher from the Flux library provides the dispatch function. Received Actions are passed to all of the registered callbacks. These callbacks are provided from the Stores.

Note: Since the Dispatcher implementation is hidden, here’s a link to the source.


Stores

Under the stores directory, create and implement the following comment-store.js file.

var AppDispatcher = require('../dispatcher/app-dispatcher');

var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

var comments = [];

var CommentStore = assign({}, EventEmitter.prototype, {

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

  addChangeListener: function(callback) {
    this.on('change', callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener('change', callback);
  },

  getAll: function() {
    return comments;
  }
});

AppDispatcher.register(function(action) {

  switch(action.actionType) {

    case "CREATE_COMMENT":
      comments.push(action.comment);
      CommentStore.emitChange();
      break;

    default:
  }
});

module.exports = CommentStore;

There are two segments of code; Store creation and Store registration (with the Dispatcher).

The Store is created by merging an EventEmitter.prototype object and a custom object, similar to the Dispatcher creation. The EventEmitter.prototype imbues the Store with the ability to subscribe to and emit events.

The custom object defines public functions for subscribing and unsubscribing to change events. It also defines a getAll function which returns the comments data.

Next, the Store registers a function with the Dispatcher. When the Dispatcher calls dispatch it passes its argument, which is an Action, to each registered callback function.

In this instance, when an Action is dispatched with an Action Type of CREATE_COMMENT, the CommentStore will push the data into its comment array and invoke the emitChange function.


Now we need a View to display the Store’s comments and subscribe to changes.

Inside the views directory find the comments.js file. Amend it to match the following.

var React = require('react');

var CommentStore = require('../stores/comment-store');

function getStateFromStore() {
  return {
    comments: CommentStore.getAll()
  }
}

var Comments = React.createClass({

  onChange: function() {
    this.setState(getStateFromStore());
  },

  getInitialState: function() {
    return getStateFromStore();
  },

  componentDidMount: function() {
    CommentStore.addChangeListener(this.onChange);
  },

  componentWillUnmount: function() {
    CommentStore.removeChangeListener(this.onChange);
  },

  render: function() {
    var comments = this.state.comments.map(function(comment, index) {
      return (
        <div className='comment' key={'comment-' + index}>
          {comment.text}
        </div>
      )
    });

    return (
      <div className='comments'>
        {comments}
      </div>
    );
  },
});

module.exports = Comments;

Most of this is familiar React code with the addition of requiring the CommentStore and a few Store related extras.

The getStateFromStores function retrieves comment data from the Store. This is set as the initial component state within getInitialState.

Inside componentDidMount the onChange function is passed to the Store’s addChangeListener function. When the Store emits a change event onChange will now fire which sets the component’s state as the updated Store data.

Lastly componentWillUnmount removes the onChange function from Store.


Conclusion

We now have a working Flux application and have touched on every core concept of the pattern; Views, Stores and the Dispatcher.

This is the essence of Flux. The Dispatcher sends data to all Stores which update and notify their Views.

At this point Flux will still feel a little unfamiliar. I highly reccommend reading the official documentation and watching the intro to Flux talk to get a deeper understanding of the Flux architecture and to further ingrain the pattern. I also suggest now reading the official examples.

If I’ve made a mistake or it doesn’t quite click for you, ping me on twitter or better yet make a pull request. Also, feel free to make suggestions for improving this guide.