React JS Flux: The Flux was introduced by Facebook which used internally while working with react. It is just an architecture that deals with react and unidirectional dataflow. This specifies that Facebook provides a reprocess that has a Dispatcher library and dispatcher is a sort of global pub or sub handler that is used to broadcast payloads of registered callbacks. Flux architecture has quite eased for Dispatcher library like node JS EventEmitter module to set up an event system that helps to manage the application state.
React JS Flux Components
The individual components in the Flux are explained below
Action: It is a helper method that passes data to the Dispatcher.
Dispatcher: It is used to receive action and to broadcast payloads to registered callbacks.
Stores: These are containers for applications that have callbacks registered to the dispatcher.
Controller View: The react components which consider the state from stores and pass it down through props to child components.
Let’s see this process graphically.
How API related to this?
When you are working with external data there are Actions in Flux which helps the data to flow in the Flux and the following Stores.
The Dispatcher
The Dispatcher is also called as a manager of the entire process because it is the central process of the hub. The Flux Dispatcher is used to receive actins and dispatches these actions and data to registered callbacks.
What is the use of pub/sub?
The pub/sub handler is not essential in the Flux in React JS. The Dispatcher itself broadcasts the payload to all registered callbacks which have functionality allows to invoke the callbacks in particular order and also waiting for updates before proceeding. There is only one dispatcher that acts as the central hub in your application.
use of pub/sub Example
var Dispatcher = require('flux').Dispatcher; var AppDispatcher = new Dispatcher(); AppDispatcher.handleViewAction = function(action) { this.dispatch({ source: 'VIEW_ACTION', action: action }); } module.exports = AppDispatcher;
In the above example, we created an instance of our Dispatcher and also create a handleViewAction method. This abstraction will help when you want to compare view triggered actions v.s. server/API triggered actions.
Here we created a method calls the dispatch method that broadcasts the payload of registered callbacks. This action can act within the stores and result in a state update.
Dependencies
The Dispatcher module defines the dependencies and marshall the callbacks on stores. Hence if one part of our application is dependent and other parts will update first with render property and the Dispatcher’s waitFor method is very useful.
For this future, we need to store the return value of the dispatcher’s registration method as a dispatched index on our store as mention below.
ShoeStore.dispatcherIndex = AppDispatcher.register(function(payload) {});
Now while using Dispatcher’s waitFor method to ensure ShoeStore must be updated.
case ‘BUY_SHOES’:
Dependencies Example
AppDispatcher.waitFor([ ShoeStore.dispatcherIndex ], function() { CheckoutStore.purchaseShoes(ShoeStore.getSelectedShoes()); }); break;
Stores
The stores in Flux are used to manage the application for a particular domain. In order words that stores manage data, data retrieval methods, dispatcher callbacks.
Stores Example
var AppDispatcher = require('../dispatcher/AppDispatcher'); var ShoeConstants = require('../constants/ShoeConstants'); var EventEmitter = require('events').EventEmitter; var merge = require('react/lib/merge'); // Internal object of shoes var _shoes = {}; // Method to load shoes from action data function loadShoes(data) { _shoes = data.shoes; } // Merge our store with Node's Event Emitter var ShoeStore = merge(EventEmitter.prototype, { // Returns all shoes getShoes: function() { return _shoes; }, emitChange: function() { this.emit('change'); }, addChangeListener: function(callback) { this.on('change', callback); }, removeChangeListener: function(callback) { this.removeListener('change', callback); } }); // Register dispatcher callback AppDispatcher.register(function(payload) { var action = payload.action; var text; // Define what to do for certain actions switch(action.actionType) { case ShoeConstants.LOAD_SHOES: // Call internal method based upon dispatched action loadShoes(action.data); break; default: return true; } // If action was acted upon, emit change event ShoeStore.emitChange(); return true; }); module.exports = ShoeStore;
Here we extend our store with NodeJS EventEmitter that allows our stores to listen or broadcast events that allow our components or views to update on events. The Controller View listens to our stores which allows us to change events and let us know that our application has changed and to retrieve the state.
We have registered callback with AppDispatcher with register method i.e., our store is listening to AppDispatcher. And the switch statement specifies for any relevant action to consider if it happens then the change event is emitted and the views get updated.
To retrieve all shoes in our_shoes object and to use data in our components we use public method getShoes by the Controller View. With the help of this example, any complicated logic can be placed instead of our views which helps to reduce things.
Action Creators & Actions
The Action Creators are the collection of methods that can be called inside the Views and send actions to Dispatchers. These Actions are payloads that delivered through the dispatcher. Facebook uses the action constants to define what action should occur and to send action data. Within the registered callbacks, the actions are handled with their action type and with action data the methods are called arguments.
Actions Example
var keyMirror = require('react/lib/keyMirror'); module.exports = keyMirror({ LOAD_SHOES: null });
Here we used React’s keyMirror library because our value matches the key definition. Now we are calling load shoes and make sure that things are in order which delivers a high-level view of application does.
Action Creator definition
var AppDispatcher = require('../dispatcher/AppDispatcher'); var ShoeStoreConstants = require('../constants/ShoeStoreConstants'); var ShoeStoreActions = {loadShoes: function(data) { AppDispatcher.handleAction({ actionType: ShoeStoreConstants.LOAD_SHOES, data: data }) } }; module.exports = ShoeStoreActions;
In the above example, we use the method our ShoeStoreActions object that calls our dispatcher with data. Now you can import this action file and call ShoeStoreActions.loadShoes which contains our data is used to send a payload to Dispatcher will broadcast it. The Shoe Store will listen to the event and calls the method that loads shoes.
Controller Views
The Controller Views in React Components are used to change events and retrieve an application from stores. They can pass data to their child components through props.
Controller Views Example
/** @jsx React.DOM */ var React = require('react'); var ShoesStore = require('../stores/ShoeStore'); // Method to retrieve application state from store function getAppState() { return { shoes: ShoeStore.getShoes() }; } // Create our component class var ShoeStoreApp = React.createClass({ // Use getAppState method to set initial state getInitialState: function() { return getAppState(); }, // Listen for changes componentDidMount: function() { ShoeStore.addChangeListener(this._onChange); }, // Unbind change listener componentWillUnmount: function() { ShoesStore.removeChangeListener(this._onChange); }, render: function() { return ( <ShoeStore shoes={this.state.shoes} /> ); }, // Update view state when change event is received onChange: function() { this.setState(getAppState()); } }); module.exports = ShoeStoreApp;
Here in the above example, we use addChangeListerner to change events and updates the application when we received our event.
Combining all Together
Till now we have seen all the components individually in the Flux components. So we good idea how the architecture will work and don’t forget our graphical representation of this process and you can see the function of each part in the flow.