Software systems to innovate and grow

State Management in React Apps

By Engineering Team June 24, 2019 10 mins read

State is an object that defines the current condition of our application. Since React is a component-based UI library, which uses state to track the moving parts of the user interface, state management in applications is very important to understand. Understanding each will help you to make an educated decision on which to use in your own projects, creating an end product that is more efficient based on your specific needs.

State Management at Component Level

React allows developers to use state at the component level by using class-based components. Since the release of React 16.8 and the advent of React Hooks, state now has functional components as well.

State With Class Components:

State is initialized in the constructor, or directly as a data member.

It can be modified using setState. Though it is mentionable that it is not advisable to modify the state directly, as this can lead to your state becoming unpredictable.

State With React Hooks:

React Hooks provide a useState function to initialize your state by accepting the initial state as an input. To modify it, it returns the state and a function.

Use setCounter (or whatever you choose to call it) to update the counter state.

This is one example. State can be used in many different ways. Couple this feature with the component-based nature of React, which allows us to intermingle state inside multiple components, and you are able to create highly dynamic and complex applications.

The Problem With State Management

Since component state can be passed around in props, it becomes confusing quickly. For example, if you need to pass the state deep inside a component tree to a child, you have to pass it through every component in between. This is called prop-drilling, and it makes it increasingly difficult to keep track of your state or modify any code in the future as it turns into a tedious process.

To solve the problem of prop-drilling, developers working with React often use some sort of state management tool. This is where many people switch to Redux to manage state. However, that may not always be the right choice.

Here are the most common ways to manage your state in React.

Context API

React Context API is the built-in state management solution, officially recommended by the React team. It was released in a stable build in React 16.3 and aims to solve the issue of prop-drilling. Context is useful if you have a state object associated with the root component needing accessed somewhere down the component tree.

The Context API consists of Providers and Consumers. Providers are wrapped over child components which may require the parent’s state. Therefore, the state, or any functions used to modify the state, must be passed through as a ‘value’ prop to the Provider. When you want to access the state or its functions, simply initialize the context you created inside the child component, and access the values directly. Another way is to wrap the component inside a Consumer component and manually pass the props. The takeaway is you don’t need to do this through tedious levels of components when you modify the state to only access the ones where you need access to the required values.

Getting started with Context is as simple as that. Notice how the middle component is left untouched, allowing simple access to what was passed from the root component (App) directly to the BottomComponent.

Redux

While learning React, almost every developer comes across Redux. At first, it seems complex and absolutely unnecessary. Some of the questions many new developers have on their mind when learning Redux are, “Why do I need to separate my state?” And, “What are all these new terms and how did my folder structure become so messy?”

At the core, Redux is a predictable state container, which has a central store where the state is saved. That store can be modified through a reducer, which is a pure function making any state changes very predictable. An action is an object with a type and a payload, which is dispatched from our component when you want to modify the state. The reducer looks out for the dispatched type, and when it matches it executes the state change.

State Management in React Apps

This is the simplest way to what a reducer looks like.

Here you see a switch-case inside the reducer, which checks for the action type, and upon matching, modifies and returns the new state to the store in a predictable manner.

To dispatch actions from our components, we need to connect them by wrapping them in a connect higher order component, provided by react-redux before exporting.

Here, mapStateToProps and mapDispatchToProps are functions, which inject the reducer state and actions to the props of our component. This way it’s easily able to interact with Redux.

Middleware can be applied to Redux to provide additional functionality such as async API calls. The three widely used middlewares available for Redux are Thunk, Redux Saga and Observable. Each has its own pros and cons. Redux Thunk is a great library to start with for beginners, as it has a low learning curve and doesn’t allow for a lot of extra or customized features. Redux also has great developer tools and a logging feature, which you can use to debug your code.

Other Mentionable Libraries

Unstated

Unstated builds on top of the Context API, while staying close to the React way of thinking. It allows you to create containers for your state and related functions to modify the state. It also allows you to subscribe to the changes in that container.

MobX

Another less commonly used library for state management is MobX, which is quite similar to Redux at the core. Where it differs is it allows you to have multiple stores and impure reducers, which may or may not be useful to you depending on where and how you want to use it.

Take it Away

There are many state management solutions available for React and each is useful depending on your specific use case. Try each and analyze the different solutions available to help you choose the best option for the scope of your project.