ReactJS for Noobs II — Flux

Sajith Dilshan
codeburst

--

This post is a continuation of ReactJS for Noobs post and if you haven’t read it already, first go through it before continuing with this article. ReactJS is a library to manipulate the web page DOM and when building a complex web app, it is paramount to manage the state of the application and most of the time React components want to talk with each other.

If all the components start to talk with each other, the whole app will be a mess and debugging an issue would be a nightmare. Hence, Flux can be used to make our lives easier. Flux is a data unidirectional architecture pattern. It is mostly a concept, rather than an implementation. First, let’s get a good conceptual understanding of what flux is and later on move on to an example implementation to get hands-on experience.

Flux in a Nutshell

Flux architecture pattern mainly consists of four components
1. View
2. Action
3. Dispatcher
4. Store

Let’s start with the View. The view is the user-visible layer which consists of React Components. Users can interact with React components since a component is mostly an HTML segment rendered on the web page. When a user interacts with a component an action can be invoked, such as showing a pop-up message when a button is clicked, and changing the color of a DIV element on mouse hover and so on.

This moves to the next component, Action. In the above-mentioned example, a user clicking on the button is the event and showing a pop-up message is the action. There can be may predefined actions and for each event, a React component can invoke an action.

When an action is invoked, the dispatcher dispatches the action to the store. The dispatcher is responsible for the wiring of React components and Stores via actions. That means whenever a component invokes an action, the dispatcher will dispatch the action to all the registered stores.

Next component is the Store, which is just an object extended from event emitter which acts as a data store. This data store keeps the state of the complete application or the state of a part of the application. When an action is dispatched to the store, the store can change its state based on the action. As an example when an action to change the color of a DIV is dispatched, the store can change its current state to reflect the new color for the DIV.

Now comes the last part. When a store changes its state, how can the React components update their component states so that ultimately the change is reflected on the web page? This is done by event listeners. A react component can register an event listener for a particular store and when the store changes its state, it will emit an event. The React Component which is listening to these events will be notified and no the component can query the new state of the store and update its component state. Below diagram summarizes connection between all these components.

Figure 1: Flux architecture diagram

Flux in Action

In this hands on tutorial we are going to build a basic React app with two components as shown in figure 2 and see how these two components can communicate with each other.

Figure 2: Components in the app

First, let’s create a react app by executing below command

create-react-app flux-example

Next, let’s add flux dependency to our app by executing below command

npm install --save flux

For this example app, apart from the boilerplate code we need two components. First let’s create a directory called components (in src directory) and within that create a file named ButtonComponent.js with below content.

As you can see the component will render two buttons with Red and Blue labels. Next within the same directory, create a ColorComponent.js file with below content.

As you can see, the component just renders a DIV with lightgrey background color. Next modify the content of App.js file as below.

Further, after adding below styles to index.css file and executing npm start and opening http://localhost:3000/ in your browser, you should see the content of the app which is similar to figure 2.

Although we have the skeleton of our app configured, clicking on the buttons will not make any change to our color component. To address that, first create a Dispatcher.js file in the src directory with below content.

This is the dispatcher for our app which will dispatch actions invoked in components to the registered stores. Now when the user clicks on a button we need an action to be invoked. For that create a directory named actions (within src directory) and within that create a file named ColorAppActions.js with below content.

You can create an action file for each component or only one file for your complete app. But it would be easier to maintain the app by keeping a separate action file for each main component. In the above code as you can see changeColor(colorName) function is exposed, so that our ColorComponent can use it to notify the change of color. Within that function we invoke the dispatch() method of the dispatcher with an object with two keys as a method argument. The type represents a unique name (throughout the app) to distinguish the action and value contains the additional information associated with the action. You can include any number of additional key-value pairs in this object. Next we need to update our ButtonComponent as shown below.

When user clicks on a button we have configured the component to invoke onButtonClick method through onClick synthetic event. Further, for each invocation we pass the name of the color as a method argument. Within the onButtonClick method, we invoke our changeColor() action.

Next, let’s move on to the store. Create a directory named stores (Within src directory) and create a file named ColorAppStore.js within that directory with below content.

This is the data store of our App. As you can see it is extended from EventEmitter because once the data in the store changes, the store will emit events so that subscribed components can update their respective states. In this store we have only one data at the moment, i.e. activeColor which represent the current background color of the ColorComponent.

const colorAppStore = new ColorAppStore();

dispatcher.register(colorAppStore.handleActions.bind(colorAppStore));

As for any store, above two lines are salient. First one creates a new instance of the store and second one registers the store with the dispatcher through a handler function so that whenever the dispatcher fetches an action, the handler function of the store will be invoked with respective action as a method argument to the handler function. In this example, the handleActions() method in the store will be invoked for any action invocation.

Within the handleActions() method, the store can query for the identifier of the action (type) and if the action is relevant to the store then the store can act upon it or if that is not the case, simply ignore the action altogether. In our case, for COLOR_APP_ACTIONS.CHANGE_COLOR we want the store to modify its activeColor accordingly and emit an event to notify the components that a change in the store has occurred. This is accomplished through below code.

this.activeColor = action.value;

this.emit(“storeUpdated”);

Next we need to update our ColorComponent as shown below to catch events emitted by the store.

First change in the component is that in the constructor for the initial state we obtain the color from the store so that we would have a single source for the background color. Next, within the componentDidMount() lifecycle method, the component is subscribing to storeUpdated events emitted from the ColorAppStore. It is mandatory to remove the listener in componentWillUnmount() method. Otherwise the store subscription will cause a memory leak in your app. As per the above code, when the ColorAppStore emits storeUpdated event, the updateBackgroundColor() method in the component will be invoked and within that method, we update the current state of the component to reflect the change in the store.

Now if you run the app and click on the buttons you will see the background color of the ColorComponent will change as shown below.

In a nutshell, when the user clicks on a button, an action will be invoked by ButtonComponent with respective color as data and the dispatcher will fetch this action to the ColorAppStore. Next, the store will extract the color information from the action and update its store data and emit a storeUpdated event. The ColorComponent which is listening to the storeUpdated events from the store will receive the emitted event and the component will update its internal state to match with the data in the ColorAppStore.

As you can see, the store acts as the single source of truth and the components talk with each other through manipulating the data within the store. This example demonstrates the basic usage of pure flux and there are better implementations of flux which abstracts out the boilerplate code to increase the developer efficiency. One such implementation is Redux and I will walk you through the basics of Redux in the next article.

The complete source code of this example app is available at https://github.com/sajithdilshan/flux-example

Call To Action

  • Clap. Appreciate and let others find this article.
  • Comment. Share your views on this article.
  • Follow me. Sajith Dilshan to receive updates on articles like this.

--

--