Telerik blogs

Complex state in React involves managing many different state changes in many different components. There’s a library for that! I’ll recommend two, plus tell you what won’t work.

One of the hardest truths in React, that we as developers should always be aware of, is that there isn’t a simple and standard way of doing something in React.

We should always be open to considering alternatives. We should look for alternatives before making a decision that can impact our team, company and career.

We have many different React state management libraries available. We can search the term “state” on npm and it will give us thousands of packages available. React has the benefit of a huge and engaged open-source community and developers are always creating new packages for solving the most specific problems in React. Each package that comes up was created to solve a specific problem of React developers.

It’s cool to use the latest state management library that was launched last week and is trending among the community. What we don’t usually get is that each library, each package was designed with a specific problem in mind, and we should always be aware of it.

Complex State in React

We can think of React components as “blocks.” We can build as many “blocks” as we want to, and building more blocks will make our lives easier to connect them later and build our whole application.

The state in React is what makes our components behave and render in different ways—sort of like assembling our blocks in different shapes and structures. It allows us to create dynamic and interactive components, making our application more insightful to the user.

The more components, the more complex the state. We can define a complex state in React as managing many different state changes in many different React components. When we have many different components in our React tree triggering different state changes, it can cause unexpected side effects and bugs. React re-renders every time a state changes, so it’s very important to have in order how our components are going to update and which components are going to change state.

There are many different state management libraries available in React that handle complex states and help us to organize our state logic throughout our applications. We’re going to cover here a few options of how we can manage our state in React and compare the differences between each one of them.


The undoubtedly most popular state management library for React is Redux. This library, released in 2015, is one of the reasons why developers love and hate at the same time state management libraries.

Redux is a predictable state container library for managing state in React. It has a centralized store for the state that can be used and accessed across an entire application. There are two important parts in Redux: actions and reducers.

Actions are plan objects that have a “type” field and behave like events. We can think of an action as some event that was triggered inside our application.

{ type: 'increment', payload: todoText }

Reducers are pure functions that take our state and an action and return a new state. Reducers must make immutable updates, which means that they can’t modify the existing state. Reducers also don’t handle any asynchronous logic or other “side effects.”

const reducer = (state = initialState, action) {
  switch (action.type) {
    case 'increment': {
      return [
          counter: action.payload,
    case 'decrement': {
      return [
          counter: action.payload,
      return state

One of the few reasons why Redux got so popular in React is because it solved the problem of prop drilling. Prop drilling is the process of passing data as props to components that don’t need the data but only help in passing it through the tree.

Looking at the problem of prop drilling in React and how Redux solves it, many developers might think that Redux is like React Context API, but they share many differences between them that we usually don’t pay attention to.

The React Context API is not a state management tool and it only serves to make the state available to a nested tree of components. Redux is a predictable state container library that makes it easy for us to separate, manage and update state logic in React. We can see where, when and how our state has changed.

Redux is a solid option for handling and managing the state in React. It’s an open-source library with a very active community and that is always been updated.

The documentation of Redux is well-written and you can start learning how Redux works by reading it. One of the most important points for state management libraries is the documentation, and Redux has one of the best out there.


Finite state machines are everywhere, without you noticing them. Finite state machines are used in the real world in many different systems, for example, traffic lights, vending machines, elevators, etc.

A finite state machine is a model of computation consisting of a machine with a finite number of states. A finite state machine can be in one of the finite numbers of states at any given time.

The process of changing from one state to another is called transition. A transition waits, reads an input, and, after triggered, will change to a specific state depending on the current state and the event.

Here’s an example of a finite state machine:

Finite state machine

A turnstile has a finite number of states. The initial state is locked—if we try to push it, it will do nothing. If we put in a coin, then it will transition to the unlocked state. If we try to put in another coin, it will do nothing. If we push it, it will transition to the locked state again. Very simple, yet it’s super powerful.

XState is a finite state machine and statecharts library for React. It helps us to create, interpret and execute finite state machines and statecharts in React applications.

What makes XState better than other common state management libraries is that it’s safe to use because we can see our finite number of possible states. XState forces us to think about state logic first before writing the code.

import { Machine } from 'xstate';

const toggleMachine = Machine({
  initial: 'inactive',
  states: {
    inactive: { on: { TOGGLE: 'active' } },
    active: { on: { TOGGLE: 'inactive' } }

When we’re using XState, we need first to start thinking about state and transitions. How we’re going to create our machine and how we’re going to transition from one state to another.

The learning curve of XState can be a little bit harder than other simple state management libraries, but it works really well for complex states. We need to get our head together with a few fundamental computer science concepts such as finite state machines, statecharts, actor model, etc.

It’s definitely worth checking out.

useState: Not for Complex State Management

There are two ways of building a component in React. We can build a component using classes or using functions. Both ways are valid and very common in the community.

Before the release of React Hooks, we could only manage our state using class components. The release of React Hooks gave start to a new era in the React community.

We can have and manage our state in functional components. Better than that, we can create custom hooks, which are simple functions that can use the built-in React hooks and make our state logic available anywhere in our application.

import { useState } from "react";

The most-used hook in React is useState. We can use the useState hook inside a functional component and that will make our component associated with that state in particular.

The useState hook is a simple function that we can pass an initial value. It returns an array, where the first value is our state value, and the second one is a function that we use to modify our state.

const [state, setState] = useState(false);

Most of the time, the useState hook is enough for us to manage our state. When we need simple string or boolean states, for example, this hook is very helpful and intuitive. It won’t create any unnecessary code in our application and it won’t make our code harder to read or debug.

import React, { useState } from "react";

const App = () => {
  const [toggle, setToggle] = useState(false);

  return (
      <h1>toggle is {toggle ? "on" : "off}</h1>
      <button onClick={() => setToggle(!toggle)}>toggle</button>

The useState hook shines when we create a simple and small piece of state and manage it inside a single component. We don’t want to handle complex states—like forms, for example—using the useState hook. It might look like an easy task, but there are many libraries available that are better suited for complex state management—and I would recommend Redux or XState.


The possibilities that React provides us are huge. We can build almost anything using it. From the most basic cases like landing pages or blogs to the most complex, like games and ecommerce apps. We can build anything using React.

State management is and will always be one of the most important concerns for React developers. It is what makes React applications dynamic and interactive.

Sometimes choosing the right state management library for the job can be a hard task. But the right library for the job will make it easier for us to implement complex things in React.

Leonardo Maldonado
About the Author

Leonardo Maldonado

Leonardo is a full-stack developer, working with everything React-related, and loves to write about React and GraphQL to help developers. He also created the 33 JavaScript Concepts.

Related Posts


Comments are disabled in preview mode.