Flux explained for newbies - Part 4

Reading Time: 5 minutes

Introduction

Flux-CapacitorIn the third part of this article series I introduced the Dispatcher, the central hub of the Flux architecture,which is responsible for propagation of actions. I also showed, that in most implementations actions can be chained, albeit I do not recommend to make regular use of that feature. In this last part of the series I present the Action Creator which helps us to launch actions in an expressive manner.

Actions and Action Creator

In Flux the users intents to update data are expressed by Actions. An Action is considered as an object carrying usually an identifier and payload data, that will be propagated via the Dispatcher towards the targeted Store. Actions are merely of semantic nature and their providers wrap the access to the Dispatcher. This way it is possible to define a set of actions as semantic expressions that can be used by the components. These actions are provided as methods by an Action Creator, which expresses the intent of an interaction, for example addPerson(). An Action Provider creates the actions and pass them to the Dispatcher.

Action Creators create actions and call the Dispatcher

It's worth mention here, that the Action Creator is the place where you want to do any data transformation prior the dispatch, and/or executing eventual server requests. Especially the latter topic is intensively discussed by the community.

Currently, there is no real best practice where to put the asynchronous server communication. Some say, that the result of an asynchronous request may trigger new actions, that's why the Action Creator should be the correct place. Others argue that a store shall be responsible to fetch data from backend to be a true Single Source of Truth, meaning that there is only one instance of our data which is referenced only when needed elsewhere. In practice there is no much difference and I don't have any opinion about this yet. I think that - if it would be of importance - we will discover which way is favorable.

And here is how it would look like in our fictitious Flux implementation. As you may see, I also demonstrate an asynchronous request inside the Action Creator using another fabulous library called FooHttp, which is a promise based request library.

If the concept of Promises is new for you, I urgently recommend to read about it. A good starting point is Kris Kowal's Tutorial, or the MDN documentation about the native Promise object.

var productStore = FooFlux.createStore({
    id : 'productStore',
    _products : [],
    add : function(person){
        this._products.push(person);
        this.notify(this._products);
    },
    setList : function(productList){
        this._products = productList.slice(); // copy list
        this.notify(this._products);
    }
});

// Establish relations between dispatchers action names and the stores target methods
FooFlux.getDispatcher().register(function(name, data) {
    switch (actionName) {
        case 'addProduct':
            productStore.add(data);
            break;
        case 'setProductList':
            productStore.setList(data);
            break;
    }
});

var productActions = FooFlux.createActionCreator({
    id: 'productActions',
    addProduct : function(product){
        // propagate to Store via Dispatcher
        FooFlux.getDispatcher().dispatch('addProduct', product);
    },
    loadProducts : function(){
        // loading products asynchronously (promise based)
        FooHttp.get( window.global.config.serviceUri + '/products' )
               .then(function(response){
                    var products = response.data;
                    FooFlux.getDispatcher().dispatch('setProductList', products);
               })
               .catch(function(error){
                 // ... treat exceptions
               })
    }

});

var productEditor = FooComponentLib.createComponent({

    product : {}, // internally updated via common data binding
    actions : FooFlux.getActions('productActions'), // our action context for this component

    onAddButtonClick : function(){
        // execute action... just like that!
        this.actions.addProduct(this.product);
    },

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

});

var productList = FooComponentLib.createComponent({

    actions : FooFlux.getActions('productActions'), // our action context for this component

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

    componentReady : function(){
        // listen to store
        FooFlux.getStore('productStore').listen(this.onChanged.bind(this));
        // load all products initially...it is asynchronous, but the stores notification triggers
        // to this components update, once all products were loaded.
        this.actions.loadProducts();
    },

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

});

Conclusion

So, we made it finally. I explained the motivation behind this architectural pattern and developed gradually the entire concept. Well, I have to admit that the last diagram has a quite respectable complexity and is not very comprehensive at the first glance. Hence, to conclude this article I significantly reduce the diagram to its data flow discarding the elements multiplicity. This will lead to the very typical Flux diagram found everywhere. In this form the One-Way-Data-Flow is pretty obvious. This data flow is quite easy to understand and helps us dramatically to have control over our data, which leads to better maintainability, and finally more productivity in component based web applications.

Simplified Flux Diagram

 

If you made it until here you should have a basic understanding

  • of cascaded data flow in component hierarchies and the resulting problem
  • that Flux is an architectural pattern
  • the motivation for this pattern
  • what the difference is between Store and Model
  • of the Dispatchers responsibility
  • the meaning of an Action Creator

Now, that you may have a pretty good idea of Flux, you should not hesitate to use it in your application. I learned Flux the hard way, as I did not used it from the beginning, although it is a very simple concept once you understood. Finally, it is all about practice, but I swear... component based (web) applications without Flux is a No-Go for me! It makes things so easy.

Facebooktwittergoogle_plusredditpinterestlinkedin

Leave a Reply

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