Flux

Create Flux containers by extending from the base Flux (or Flummox) class.

class Flux extends Flummox {
  constructor() {
    super();

    // Create actions first so our store can reference them in
    // its constructor
    this.createActions('messages', MessageActions);

    // Extra arguments are sent to the store's constructor. Here, we're
    // passing a reference to this Flux instance
    this.createStore('messages', MessageStore, this);
  }
}

Encapsulate your stores and actions

Flummox is designed to be used without singletons. Instead, create a Flux class that encapsulates the creation of all your application’s stores and actions, so that you can create new instances on the fly.

const flux = new Flux();

(Note that there’s nothing technically stopping you from using singletons if you wish, but why would you want to?)

Debugging

Like Stores, Flux instances are EventEmitters. A dispatch event is emitted on every dispatch. Listeners are sent the dispatched payload. This can be used during development for debugging.

flux.addListener('dispatch', payload => {
  console.log('Dispatch: ', payload);
});

Additionally, an error event is emitted when errors occur as a result of an async action. This is both for convenience and to prevent error gobbling.

Methods

createActions

Actions createActions(string key, function ActionsClass [, ...constructorArgs])

Creates an instance of ActionsClass and saves a reference to it. constructorArgs are passed to the constructor of ActionsClass on creation.

createStore

Store createStore(string key, function StoreClass [, ...constructorArgs])

Creates an instance of StoreClass, registers the store’s handlers with the dispatcher, and saves a reference to it. constructorArgs are passed to the constructor of ActionsClass on creation.

getStore

Store getStore(string key)

Gets an store instance by key.

removeStore

Store removeStore(string key)

Deletes an instance of StoreClass, unregisters the store’s handlers from dispatcher, and removes all store listeners.

getActions

Actions getActions(string key)

Gets an actions instance by key.

getActionIds

Actions getActionIds(string key)

Gets action ids for the given actions key. Internally calls Actions#getActionIds.

Also available as getConstants().

removeActions

Actions removeActions(string key)

Deletes an actions instance by key.

Dispatcher methods

Every Flux instance has its own dispatcher. You should try to avoid interacting with the dispatcher directly, but it is available (primarily for testing purposes) as this.dispatcher. Some convenience methods are also provided:

dispatch

dispatch(string actionId [, * body])

Similar to the dispatch() method of the dispatcher itself, except instead of passing a payload, the payload is constructed for you, in the form:

{
  actionId,
  body
}

This is used internally by Flummox: the actionId field is used to identify the source action, and body contains the value passed to store handlers. In your tests, you can use it to simulate a dispatch to your stores.

waitFor

waitFor(Store store)

Similar to the waitFor() method of the dispatcher itself, this can be used within a handler to wait for a different store to respond to the dispatcher before continuing. The operation is synchronous.

Instead of passing a store, you can also pass a dispatcher token, or an array of tokens and stores.

Using a custom dispatcher

tl;dr Flummox uses the flux dispatcher from Facebook, but you can switch out whatever api compatible dispatcher you want.


Usually the dispatcher provided by Facebook is sufficient, but you aren’t limited to using it if you find you need more than it provides. If you want to have custom behavior when dispatching actions, you can provide a wrapper for the Facebook dispatcher that does what you want. Or use something else entirely. It’s up to you.

To substitute a different dispatcher object just change the constructor() function of your flux object like this:


class Flux extends Flummox {
  constructor() {
    super();

    this.dispatcher = new MyCustomDispatcher();
  }
}

Just remember, whatever object you provide has to follow the same api as the dispatcher from Facebook. The easiest way to do that is to extend the Facebook dispatcher in a new class, and then provide whatever alternate or extended functionality you desire.

For instance, say you want to allow the dispatcher to receive actions for dispatching while it is in the middle of another action dispatch. The standard dispatcher will complain that you cannot dispatch an action during another action. There are good reasons for this, but perhaps you just want to queue up that action and have it execute when the current action is completed. One easy way to do this would be to use setTimeout(). To do this you would provide a dispatcher with slightly different dispatch functionality, like this:


class MyCustomDispatcher extends Dispatcher {
  dispatch(...args) {
    if (!this.isDispatching()) {
      super.dispatch(...args); // This will execute the Facebook dispatcher's dispatch function.
    } else {
      setTimeout(() => { // We are currently dispatching, so delay this action using setTimeout
        super.dispatch(...args);
      }, 0);
    }
  }
}

Serialization/deserialization

If you’re building an isomorphic application, it’s often a good idea pass the initial state of your application from the server to the client to avoid unecessary/duplicate HTTP requests. This is easy with Flux, since all of your application state is located in your stores.

This feature is opt-in on a store-by-store basis, and requires some additional set-up.

serialize

string serialize()

Returns a serialized string describing the entire state of your Flux application.

Internally, it passes each store’s current state to the store’s static method Store.serialize(). The return value must be a string representing the given state. If a store does not have a static method serialize(), or if it returns a non-string, it is ignored.

deserialize

deserialize(string stateString)

Converts a serialized state string (as returned from Flux#serialize()) to application state and updates the stores.

Internally, it passes the state string for each store (as returned from Store.serialize()) to the store’s static method Store.deserialize(). The return value must be a state object. It will be passed to Store#replaceState(). If a store does not have a static method deserialize(), it is ignored.