Home Learning React - Managing state with React Redux
Post
Cancel

Learning React - Managing state with React Redux

Designing your application using a component-based architecture is a first step towards a nice decoupled design. But with great power comes great complexity! Components might need to interact in different ways in order to achieve some common goals. How can components communicate with each other? In this post, I am going to show how to make components communicate by using the redux pattern.

Source Code

Code outlined in this article can be found on GitHub.

State in React's components

In the previous post, I blogged about React's components and how to manage state internally in a component. Although working with state within a component is great, it is limiting as well, as this state is only local, it does not travel to other components within the same application. In some cases this is fine, but in other scenarios, like in more complex applications, communication is vital. Components might want to react on actions that are sourced from other component state changes.

There are various ways to support component communication, but I would like to talk about the Redux pattern in this post.

Redux

Redux is pattern, based on the Flux pattern that Facebook introduced. Let me quickly introduce you to the gist of these patterns by first exploring quickly the Flux and then the Redux patterns. (disclaimer: image on Flux comes from the official Facebook docs page).

Flux

Intent: A unidirectional data flow pattern to notify state changes in component-based architecture applications.

Image 1 - Flux pattern
Image 1 - Flux pattern

Participants:

  • Dispatcher. Receives and emits actions to stores.
  • Store. Receives actions, which mutate state, which in turn update the controller view.
  • Action. Indicates data/state change.
  • View. Receives state/data changes that render in UI, but also emits actions which update data/state based on UI interactions.

There is a central dispatcher for the application. That dispatcher receives actions, which might come from a view or might come from other entities like a service or a timer. Dispatcher is then broadcasting actions to the stores, which might be more than one, and each store updates itself based on the incoming action. Finally, each store is updating its related controller view by emitting a change event to that view.

Redux

Redux is based on the Flux pattern I mentioned above, but it has three extra principles.

  1. Store is now a singleton, the single source of truth.
  2. State is immutable.
  3. Changes are made with pure functions.

Image 2 - Redux pattern
Image 2 - Redux pattern

Participants:

  • Store. The singular source of truth, it receives actions from dispatchers, uses reducers internally to change state and also emits data/state changes to controller views.
  • Action dispatchers. This is a dispatcher that listens to view events or receives actions outside a view, like a push notification or the timer API, etc. It dispatches events to the store, which contain data & action types, with the latter helping in identifying the state change that should occur.
  • Reducer. It is a pure function, which receives the state and the current action and provides as output the new state or if the action type does not match the reducer type, the current state, untouched.
  • View.Receives state/data changes that render in UI, but also uses action dispatchers to dispatch events back to the store to indicate data/state changes.

Store now is the single source of truth, only one store exists for the application. This store can receive various actions which are dispatched by action creators. One or more reducers are used by the store to create a new state, while finally, the view gets its state updated via the store.

State cannot be mutated by views or anything else except the store itself. For this reason, in order to update state you need to dispatch a new event to the store and never assign to the state stored in store directly.

Finally, state is updated within the store by a reducer, which in turn is a pure function. Be advised that pure functions do not cause any side effect, which in simple words means that it will produce an output based on the input it gets without changing the input.

For React, Dan Abramov created the Redux library that provides an implementation on the Redux pattern along with a set of helpful APIs. Please be advised, that this approach is not lean and involves complexity, so be careful and evaluate your application complexity on how redux will be able to improve the situation. If your application is relatively simple, redux might not be the way to go. Check this section from the official redux website for more information on where redux might be useful.

Application

First I will start by downloading the redux npm package

npm i react-redux --save

That's it, I don't need to change webpack, or anything else, only my React code. Let's deep dive into the changes, by first exploring the store.

Store

Let's first define the state that the store is going to manage and the action types that it is going to allow. If you have been following along, in the previous post, I had created a single component, that had one textbox. Based on user's input in that textbox, another area within the view was being updated, by receiving state changes and rendering state in the view. So, pretty much the application's state here is just a string, the input that the user types in the textbox. I can name the action type whatever I want, in this case I will name it NAME_CHANGE.

As discussed earlier about the Redux pattern, I need a reducer for my store. I am going to create a reducer that is going to receive a state in a string form (the textbox content) and the action type I mentioned above. Then I will create my store using this reducer.

Pretty much what I described earlier. When the action type matches the state changes to this action value and when it does not match, state returns untouched.
I will use that store throughout my application components.

Main

Now that I have the store, it is time to actually use it. I import the store in the main.js file, in which I subscribe the main render function with the store. I am also passing the store reference to the App component, in order for the underlying components to be able to get the state or dispatch a new action.

Compared to the previous post, this application design is more granular as I have separated the concerns by defining more components. But now that I have defined different components for the form and for the input content that is displayed, I have to find a way to make these components to communicate.

Separating concerns with components

The App component is the root component for the application. But it gets more granular as App uses the Jumbotron, FormContainer and Greet components.
FormContainer, as the name implies, it serves as a container component, which in turn is encapsulating logic within the child NameForm component.

Remember that in main.js, I passed a store reference to the App component in order to pass this further to child components that might depend on it. I am getting the store reference from the props object and I pass it to the FormContainer and Greet components respectively. First is using the store to dispatch state changes, while the latter is retrieving the state from the store to render in the view.

The Jumbotron component

This is a very simple component, it just receives a string as input and it renders it within a bootstrap jumbotron.

The FormContainer component

This is a simple container component, it is used to contain the NameForm component, which does all the heavy lifting.

A container is what it says, it is a component that contains other components.
Why you might want to have a container component?

  • Separate rendering and business/data concerns.
  • Being more granular, so child components can be reused.

The NameForm component

This is the place where I am using a dispatcher to dispatch the NAME_CHANGE action type to the store.
Take a look in the following code. I have an <input> element, which sets its value by using the value fetched from the store.
When the input content changes by some user interaction, the onChange event handler fires. In this case, I have defined a simple method that calls the dispatch method of the store and I pass a simple object with type as NAME_CHANGE and value as the input current text value. The type property is required.

So every time a user enters or deletes any character in the textbox, store will be notified for this action and it will change the state. This is going to affect other components that are interested in that particular state, like the Greet component.

The Greet component

This component renders the textbox contents, so it is technically listening for changes over the store's state.
I am just fetching the state from the store and passing it to the view to render, as you might notice in the render method, using the store.getState() method.

Below you can see everything in action, it is working exactly like before in the previous post.

Although this code seems to work and the problem of component communication seems to be weathered, I really don't like the fact that component's know about the store. They shouldn't even care, yet it is passed as dependency. In next post I will try to find a way to eliminate this dependency from the component's and make code less cluttered.

Summary

In this post you saw what is the Redux pattern and how you can use the React Redux library in your application to make components communicate.
You might need to take a bit more in depth look in Redux, learn more about the library and the use cases that it can be incorporated into. Redux is not recommended to be used in simple scenarios. Take a look at Dan Abramov's Egghead free course for more information on react redux.

If you liked this blog post and found it useful, please like, share & subscribe for more! Also, if not yet a follower, follow me on Twitter!


This post is part of the Learning React series

This post is licensed under CC BY 4.0 by the author.

Learning React - Components and state

ASP.NET Core 2.0 Authentication with Azure Active Directory

Comments powered by Disqus.