Flux explained for newbies - Part 2

Reading Time: 5 minutes

Introduction

Flux-CapacitorIn the first part of this article series I started to talk about "WHY?" using Flux. Using a simple form component as example I demonstrated, that we need to decide how our form data flows. I concluded the post, that the inherent way of how data flows in component based application can be quite cumbersome, especially if a complex component consists of a multi-layered component-hierarchy. Traditional data-binding (may it one-way, or two-way) leads to a chain of re-passing data down- and upwards the component tree. Extrapolating the given problem we can depict the problem in a more generic way.

Generic Data Flow in CBD

 

 

Flux - An architectural pattern

To overcome this problem the smart guys at Facebook "invented" an architectural pattern called "Flux". This pattern separates the data flow from components. Just to clarify: Flux is a concept and not an implementation. Of course, Facebook provides their own (at least partial) implementation of this pattern, but there are a lot of more in the wild. Currently, the community is in the phase of understanding the concept, and therefore many implementations are surging. It is just a matter of time, when this gets consolidated by the community.

Leveraging this topic it's worth mention, that I also developed an implementation of the Flux pattern. I called it nanoflux, as it is a very lightweight (<3 KiB), agnostic, and true Flux implementation.

The Store

With the idea of separating the data from the components we could think - at a first glance -  of a kind of a model, that is provided independently of a components structure. Using the terms established by Facebook for the Flux pattern, we call the model Store. More precisely, a Store maintains one or more models, that's one reason why it is called Store and not model. As we have the data inside of our store, we might pass the data processing to the store also. This way we obtain the following architecture:

Models separated from components

In this moment, I need to clarify that the data stored in a store represents an application state. As a rule of thumb you can think of an application state as everything that need to be visualized directly or indirectly. For example, you would store data of an entity like a person or product, but not an authentication token.

This new scenario does resolve our problem of re-passing data along the component hierarchy. Now, we have all data stored separately, but a store is more than just maintaining the data. The Flux pattern determines that a Store is the only one who knows to manipulate its maintained data. Its responsibility is to update data and inform interested components about changes. In the above picture it seems that the components pass only data to the store in a bidirectional manner, saying that updating data belongs to the components, which may lead to redundant code. So, in a more sophisticated version we put the updating logic in the Store:

flux-step2

 

This way our notified components does not care about how to update data, and just re-renders the changed data. Of course, it is possible to introduce more Stores, where each helps to structure your entire application. It is usual to create one Store per domain, for example a PersonStore and a ProductStore. This way data is separated logically, and the view (represented by our components) can be updated accordingly, but leads to more complex architecture. Commonly, a Store provides a set of methods, for example add(), update(), delete() to update its models. So, each Store may have its own interfaceflux-step-1

 

Now, we have a quite flexible situation, with several components updating the stores, and other components listening to them. Using exactly this scheme in a real world application we would need to

  1. Create a store, defining its model and interface
  2. Make one or more components listen to the store
  3. Update the store inside one or more component

Let's see this as code. Assume we have a fictitious Flux library called FooFlux, and a component personEditor, that updates the store (by adding a person item) and a component personList that represents a list of persons and listens to the store personStoreFooComponentLib is also a non-existing component based rendering library used just for demonstration purposes.

var personStore = FooFlux.createStore({
    id : 'personStore',
    _persons : [], // our person model
    add : function(person){
        this._persons.push(person);
        // notify all listening components
        this.notify(this._persons);
    }
});

var personEditor = FooComponentLib.createComponent({

    _personStore : FooFlux.getStore('personStore'),

    _getInternalPersonData: function(){
        // ... logic to get this components person data
        // in real world libs the data may be available automatically 
        // via data binding
    },

    onAddButtonClick : function(){
        // update store
        personStore.add(this._getInternalPersonData());
    },

    render : function(){
        // .. code for rendering
    }

});

var personList = FooComponentLib.createComponent({

    // called when store was updated
    onChanged : function(persons){
        this._persons = persons;
        this.render();
    },

    componentReady : function(){
        // listen to store
        FooFlux.getStore('personStore').listen(this.onChanged.bind(this));
    },

    render : function(){
        // .. code for rendering
    }

});

Reading until here, you should have a quite good idea, what a Store in the context of Flux means. In the next part I will introduce another essential element of the Flux pattern - The Dispatcher.

 

 

Facebooktwittergoogle_plusredditpinterestlinkedin

Leave a Reply

Your email address will not be published. Required fields are marked *