HOME>BLOG>
10 Most Popular State Management Libraries in React

10 Most Popular State Management Libraries in React

A glimpse on the most popular state management tools in React and how to apply them

Learning
Web Development
November 19th, 2022 · 7 min read
10 Most Popular State Management Libraries in React

State management refers to the process of managing and manipulating the state of a React application. State is the data or variables that determine the behavior of a component, and can include things like form values, user input, and application data.

In React, state is typically managed at the component level, with each component maintaining its own state. This can be sufficient for simple applications with small or medium-sized state trees, but as the complexity of the application increases, it can become challenging to manage state in this way.

To address this issue, developers often turn to state management libraries, which provide tools and techniques for managing state in a more predictable and consistent way. These libraries allow you to store and manipulate state in a central location, rather than having to pass it down the component tree through props. This can make it easier to update and query state, and can help to prevent the need for complex props drilling.

Here are the 10 most popular state management libraries for React:

#1 Redux

Redux is a widely-used state management library that allows you to store all of your application’s state in a single store, and provides tools for updating and querying the state in a predictable and consistent way. It is especially useful for applications with complex state trees or that require the ability to undo and redo actions.

To use Redux in a React application, first, install the redux and react-redux libraries:

1npm install redux react-redux

Next, create a reducer function that specifies how the state should be updated in response to actions:

1const counterReducer = (state = 0, action) => {
2 switch (action.type) {
3 case 'INCREMENT':
4 return state + 1;
5 case 'DECREMENT':
6 return state - 1;
7 default:
8 return state;
9 }
10};

Then, create a store using the reducer function:

1import { createStore } from 'redux';
2
3const store = createStore(counterReducer);

Now, you can use the store to update and query the state of your application. For example, you can dispatch actions to the store to update the state:

1store.dispatch({ type: 'INCREMENT' });

You can also use the store’s getState method to retrieve the current state:

1console.log(store.getState()); // Output: 1

Finally, you can use the react-redux library to connect your React components to the store, allowing them to access and update the state:

1import { connect } from 'react-redux';
2
3const mapStateToProps = (state) => ({
4 count: state,
5});
6
7const mapDispatchToProps = (dispatch) => ({
8 increment: () => dispatch({ type: 'INCREMENT' }),
9 decrement: () => dispatch({ type: 'DECREMENT' }),
10});
11
12const Counter = ({ count, increment, decrement }) => (
13 <div>
14 <p>Count: {count}</p>
15 <button onClick={increment}>Increment</button>
16 <button onClick={decrement}>Decrement</button>
17 </div>
18);
19
20export default Counter;

Visit Redux.js.org for the documentation 🔗


#2 MobX

MobX is based on the concept of reactive programming. It allows you to easily manage and manipulate the state of your application by using observable data structures and reactive computations. MobX is known for its simplicity and ease of use, and is a good choice for developers who are new to state management.

Install the mobx and mobx-react libraries:

1npm install mobx mobx-react

Next, create a store class that holds the state of your application. This store should contain any variables that you want to be able to update and observe:

1import { observable } from 'mobx';
2
3class CounterStore {
4 @observable count = 0;
5}
6
7const store = new CounterStore();

Now, you can use the store to update and query the state of your application. For example, you can define methods on the store to update the state:

1class CounterStore {
2 @observable count = 0;
3
4 increment() {
5 this.count++;
6 }
7
8 decrement() {
9 this.count--;
10 }
11}
12
13const store = new CounterStore();

You can also use the store to update and query the state of your application. For example, you can call the increment and decrement methods on the store to update the state:

1store.increment();
2store.decrement();

Visit MobX.js.org for more details 🔗


#3 React Context

React Context is a built-in feature of React that allows you to pass data down the component tree without the need for props drilling. It is a simple and lightweight alternative to libraries like Redux or MobX, and is particularly well-suited for applications with small or medium-sized state trees.

To use React Context in a React application, you will need to create a context using the createContext function, and then provide the context to your components using the Context.Provider component. Here is an example of how you might use React Context to manage the state of a simple counter application:

First, create a context using the createContext function:

1import { createContext } from 'react';
2
3const CounterContext = createContext();

Next, create a provider component that wraps your application and provides the context to your components:

1import { useState } from 'react';
2
3const CounterProvider = ({ children }) => {
4 const [count, setCount] = useState(0);
5
6 const increment = () => setCount(count + 1);
7 const decrement = () => setCount(count - 1);
8
9 return (
10 <CounterContext.Provider value={{ count, increment, decrement }}>
11 {children}
12 </CounterContext.Provider>
13 );
14};

Now, you can use the CounterContext.Consumer component to access the context within your components:

1import { useContext } from 'react';
2
3const Counter = () => {
4 const { count, increment, decrement } = useContext(CounterContext);
5
6 return (
7 <div>
8 <p>Count: {count}</p>
9 <button onClick={increment}>Increment</button>
10 <button onClick={decrement}>Decrement</button>
11 </div>
12 );
13};

Finally, wrap your application in the CounterProvider component:

1import { render } from 'react-dom';
2
3render(
4 <CounterProvider>
5 <App />
6 </CounterProvider>,
7 document.getElementById('root')
8);

This will make the context available to all of the components within the CounterProvider, allowing them to access and update the state using the useContext hook.

Read more about the Context API from the React.js website 🔗


#4 Unstated

Unstated is a lightweight state management library for React that allows you to manage the state of your application using simple container components. It is based on the concept of dependency injection, and uses a declarative approach to state management by creating container components that hold and manipulate the state, and then injecting the state into your presentational components as props. Unstated is known for its simplicity and minimalistic approach to state management.

Install the unstated library:

1npm install unstated

Create a container component that manages the state of your application:

1import { Container } from 'unstated';
2
3class CounterContainer extends Container {
4 state = {
5 count: 0,
6 };
7
8 increment() {
9 this.setState({ count: this.state.count + 1 });
10 }
11
12 decrement() {
13 this.setState({ count: this.state.count - 1 });
14 }
15}
16
17const counter = new CounterContainer();

Now, you can use the container to update and query the state of your application. For example, you can call the increment and decrement methods on the container to update the state:

1counter.increment();
2counter.decrement();

You can also access the state property of the container to retrieve the current state:

1console.log(counter.state.count); // Output: 0

Finally, you can use the inject higher-order component provided by Unstated to inject the container into your components, allowing them to access and update the state:

1import { inject } from 'unstated';
2
3const Counter = ({ counter }) => (
4 <div>
5 <p>Count: {counter.state.count}</p>
6 <button onClick={counter.increment}>Increment</button>
7 <button onClick={counter.decrement}>Decrement</button>
8 </div>
9);
10
11export default inject(counter)(Counter);

Check out the unstated repository in GitHub 🔗


#5 Apollo Client

Apollo Client is a popular state management library for managing GraphQL data in React applications. It provides tools for querying and mutating GraphQL data, and allows you to easily integrate your application with a GraphQL server. Apollo Client is a good choice for developers who are using GraphQL in their applications.

Here is an example of using Apollo Client for state management in a React application:

1import React from 'react';
2import { useQuery, useMutation } from '@apollo/client';
3
4import { GET_TODO, TOGGLE_TODO } from '../queries';
5
6function Todo({ id }) {
7 const { data, loading, error } = useQuery(GET_TODO, { variables: { id } });
8 const [toggleTodo] = useMutation(TOGGLE_TODO);
9
10 if (loading) return <p>Loading...</p>;
11 if (error) return <p>Error: {error.message}</p>;
12
13 const { todo } = data;
14
15 return (
16 <div>
17 <input
18 type="checkbox"
19 checked={todo.completed}
20 onChange={() => toggleTodo({ variables: { id } })}
21 />
22 <label>{todo.text}</label>
23 </div>
24 );
25}

In this example, the useQuery hook is used to fetch a todo item with a specific ID from the server, and the useMutation hook is used to toggle the completion status of the todo item. The TOGGLE_TODO mutation updates the server and the local cache automatically with the new data.

The GET_TODO and TOGGLE_TODO queries and mutations should be defined separately. Here’s an example of how they might look:

1import { gql } from '@apollo/client';
2
3export const GET_TODO = gql`
4 query GetTodo($id: ID!) {
5 todo(id: $id) {
6 id
7 text
8 completed
9 }
10 }
11`;
12
13export const TOGGLE_TODO = gql`
14 mutation ToggleTodo($id: ID!) {
15 toggleTodo(id: $id) {
16 id
17 completed
18 }
19 }
20`;

Read the Apollo Client documentation from the Apollo GraphQL website 🔗


#6 Recoil

Recoil is a new state management library from Facebook that is designed for building large-scale applications with complex state trees. It allows you to manage your application’s state using a graph-based model, and provides tools for efficiently querying and updating the state.

1import React from 'react';
2import { atom, useRecoilState } from 'recoil';
3
4const todoListState = atom({
5 key: 'todoListState',
6 default: [],
7});
8
9function TodoList() {
10 const [todoList, setTodoList] = useRecoilState(todoListState);
11
12 const addTodo = (newTodo) => {
13 setTodoList((oldTodoList) => [...oldTodoList, newTodo]);
14 };
15
16 return (
17 <div>
18 {todoList.map((todo) => (
19 <Todo key={todo.id} todo={todo} />
20 ))}
21 <AddTodoForm onAddTodo={addTodo} />
22 </div>
23 );
24}
25
26function AddTodoForm({ onAddTodo }) {
27 const [text, setText] = React.useState('');
28
29 const handleSubmit = (event) => {
30 event.preventDefault();
31 onAddTodo({ text, completed: false });
32 setText('');
33 };
34
35 return (
36 <form onSubmit={handleSubmit}>
37 <input
38 type="text"
39 value={text}
40 onChange={(event) => setText(event.target.value)}
41 />
42 <button type="submit">Add Todo</button>
43 </form>
44 );
45}
46
47function Todo({ todo }) {
48 return <div>{todo.text}</div>;
49}

In this example, the todoListState atom is defined and initialized with an empty array. The useRecoilState hook is used to read and update the value of the todoListState atom. The TodoList component displays a list of todo items and a form for adding new todo items. The AddTodoForm component has a form with an input field and a submit button. When the form is submitted, a new todo item is added to the list by calling the onAddTodo callback prop with the new todo item.

Visit the Recoil website for more information 🔗


#7 Zustand

Zustand is a lightweight state management library that is based on the concept of hooks. It allows you to manage the state of your application using simple functions that are called inside your components, and is particularly well-suited for applications with small or medium-sized state trees.

1import React from 'react';
2import create from 'zustand';
3
4const useStore = create((set) => ({
5 todoList: [],
6 addTodo: (newTodo) => set((state) => ({
7 todoList: [...state.todoList, newTodo],
8 })),
9}));
10
11function TodoList() {
12 const { todoList, addTodo } = useStore();
13
14 return (
15 <div>
16 {todoList.map((todo) => (
17 <Todo key={todo.id} todo={todo} />
18 ))}
19 <AddTodoForm onAddTodo={addTodo} />
20 </div>
21 );
22}
23
24function AddTodoForm({ onAddTodo }) {
25 const [text, setText] = React.useState('');
26
27 const handleSubmit = (event) => {
28 event.preventDefault();
29 onAddTodo({ text, completed: false });
30 setText('');
31 };
32
33 return (
34 <form onSubmit={handleSubmit}>
35 <input
36 type="text"
37 value={text}
38 onChange={(event) => setText(event.target.value)}
39 />
40 <button type="submit">Add Todo</button>
41 </form>
42 );
43}
44
45function Todo({ todo }) {
46 return <div>{todo.text}</div>;
47}

In this example, the useStore hook is used to create a store with a todoList state variable and an addTodo action. The TodoList component displays a list of todo items and a form for adding new todo items. The AddTodoForm component has a form with an input field and a submit button. When the form is submitted, a new todo item is added to the list by calling the onAddTodo callback prop with the new todo item.

Check out the Zustand repository in GitHub 🔗


#8 XState

XState is based on the concept of finite state machines. It allows you to model the different states and transitions of your application using a simple and expressive syntax, and provides tools for updating and querying the state in a predictable and consistent way.

1import React from 'react';
2import { useMachine } from '@xstate/react';
3import { Machine } from 'xstate';
4
5const todoMachine = Machine({
6 id: 'todo',
7 initial: 'idle',
8 states: {
9 idle: {
10 on: {
11 ADD: 'adding',
12 },
13 },
14 adding: {
15 on: {
16 SUBMIT: 'idle',
17 CANCEL: 'idle',
18 },
19 },
20 },
21});
22
23function TodoList() {
24 const [current, send] = useMachine(todoMachine);
25 const { todoList } = current.context;
26
27 return (
28 <div>
29 {current.matches('idle') && (
30 <button onClick={() => send('ADD')}>Add Todo</button>
31 )}
32 {current.matches('adding') && (
33 <AddTodoForm
34 onSubmit={(newTodo) => {
35 send('SUBMIT', { newTodo });
36 }}
37 onCancel={() => send('CANCEL')}
38 />
39 )}
40 {todoList.map((todo) => (
41 <Todo key={todo.id} todo={todo} />
42 ))}
43 </div>
44 );
45}
46
47function AddTodoForm({ onSubmit, onCancel }) {
48 const [text, setText] = React.useState('');
49
50 const handleSubmit = (event) => {
51 event.preventDefault();
52 onSubmit({ text, completed: false });
53 setText('');
54 };
55
56 return (
57 <form onSubmit={handleSubmit}>
58 <input
59 type="text"
60 value={text}
61 onChange={(event) => setText(event.target.value)}
62 />
63 <button type="submit">Add Todo</button>
64 <button type="button" onClick={onCancel}>Cancel</button>
65 </form>
66 );
67}
68
69function Todo({ todo }) {
70 return <div>{todo.text}</div>;
71}

In this example, the todoMachine is a finite state machine (FSM) that manages the state of the todo list application. The useMachine hook is used to interpret the FSM and provide the current state and an action dispatcher to the component. The TodoList component displays a button for adding a new todo item or a form for adding a new todo item, depending on the current state. When the form is submitted, the new todo item is added to the list by dispatching the SUBMIT action.

Read further on the XState.js.org documentation 🔗


#9 Easy Peasy

Easy Peasy is based on the concept of a global store and an abstraction of Redux. It allows you to manage the state of your application using a single, centralized store, and provides tools for updating and querying the state in a predictable and consistent way. Easy Peasy is known for its simplicity and ease of use as tagged with being developer-friendly.

1import React from 'react';
2import { useStoreState, useStoreActions } from 'easy-peasy';
3
4const store = {
5 todos: {
6 items: [],
7 add: (state, payload) => {
8 state.items.push(payload);
9 },
10 },
11};
12
13function TodoList() {
14 const todoList = useStoreState((state) => state.todos.items);
15 const addTodo = useStoreActions((actions) => actions.todos.add);
16
17 return (
18 <div>
19 {todoList.map((todo) => (
20 <Todo key={todo.id} todo={todo} />
21 ))}
22 <AddTodoForm onAddTodo={addTodo} />
23 </div>
24 );
25}
26
27function AddTodoForm({ onAddTodo }) {
28 const [text, setText] = React.useState('');
29
30 const handleSubmit = (event) => {
31 event.preventDefault();
32 onAddTodo({ text, completed: false });
33 setText('');
34 };
35
36 return (
37 <form onSubmit={handleSubmit}>
38 <input
39 type="text"
40 value={text}
41 onChange={(event) => setText(event.target.value)}
42 />
43 <button type="submit">Add Todo</button>
44 </form>
45 );
46}
47
48function Todo({ todo }) {
49 return <div>{todo.text}</div>;
50}

In this example, the store is defined with a todos property that has an array of todo items and an add action. The useStoreState hook is used to read the value of the items state variable, and the useStoreActions hook is used to get the add action. The TodoList component displays a list of todo items and a form for adding new todo items. The AddTodoForm component has a form with an input field and a submit button. When the form is submitted, a new todo item is added to the list by calling the onAddTodo callback prop with the new todo item.

Check out the Easy Peasy repository in GitHub 🔗


#10 Valtio

Valtio is a state management library for React that uses the Observer pattern to synchronize state changes between components. It provides a simple API for managing state, including creating stores, reading and updating state values, and subscribing to state changes.

In Valtio, a store is an object that holds the application’s state variables and actions. State variables are values that represent the state of the application, and actions are functions that can update the state variables. Components can use the useStore hook to read the values of state variables and actions from the store and subscribe to updates. When a state variable or action is updated, Valtio will automatically re-render the subscribed components with the new values.

1import React from 'react';
2import { createStore, useStore } from 'valtio';
3
4const todoStore = createStore({
5 todos: [],
6 addTodo: (newTodo) => {
7 todoStore.todos.push(newTodo);
8 },
9});
10
11function TodoList() {
12 const { todos, addTodo } = useStore(todoStore);
13
14 return (
15 <div>
16 {todos.map((todo) => (
17 <Todo key={todo.id} todo={todo} />
18 ))}
19 <AddTodoForm onAddTodo={addTodo} />
20 </div>
21 );
22}
23
24function AddTodoForm({ onAddTodo }) {
25 const [text, setText] = React.useState('');
26
27 const handleSubmit = (event) => {
28 event.preventDefault();
29 onAddTodo({ text, completed: false });
30 setText('');
31 };
32
33 return (
34 <form onSubmit={handleSubmit}>
35 <input
36 type="text"
37 value={text}
38 onChange={(event) => setText(event.target.value)}
39 />
40 <button type="submit">Add Todo</button>
41 </form>
42 );
43}
44
45function Todo({ todo }) {
46 return <div>{todo.text}</div>;
47}

In this example, the todoStore is a store object with a todos state variable and an addTodo action. The useStore hook is used to read the value of the todos state variable and the addTodo action from the store. The TodoList component displays a list of todo items and a form for adding new todo items. The AddTodoForm component has a form with an input field and a submit button. When the form is submitted, a new todo item is added to the list by calling the onAddTodo callback prop with the new todo item.

The useSnapshot hook in Valtio is used to get a snapshot of the current state of a store. It returns an object with the values of all the state variables in the store at the time the hook is called.

1import { createStore, useSnapshot } from 'valtio';
2
3const todoStore = createStore({
4 todos: [],
5 addTodo: (newTodo) => {
6 todoStore.todos.push(newTodo);
7 },
8});
9
10function TodoList() {
11 const { todos, addTodo } = useStore(todoStore);
12 const snapshot = useSnapshot(todoStore);
13
14 console.log(snapshot); // { todos: [ { text: 'Take out the trash', completed: false }, ... ] }
15
16 return (
17 <div>
18 {todos.map((todo) => (
19 <Todo key={todo.id} todo={todo} />
20 ))}
21 <AddTodoForm onAddTodo={addTodo} />
22 </div>
23 );
24}
25
26function AddTodoForm({ onAddTodo }) {
27 const [text, setText] = React.useState('');
28
29 const handleSubmit = (event) => {
30 event.preventDefault();
31 onAddTodo({ text, completed: false });
32 setText('');
33 };
34
35 return (
36 <form onSubmit={handleSubmit}>
37 <input
38 type="text"
39 value={text}
40 onChange={(event) => setText(event.target.value)}
41 />
42 <button type="submit">Add Todo</button>
43 </form>
44 );
45}
46
47function Todo({ todo }) {
48 return <div>{todo.text}</div>;
49}

The useSnapshot hook is called with the todoStore as an argument. It returns an object with the values of all the state variables in the store, which can be logged to the console or used in other ways.

Take a glimpse at the Valtio repository in GitHub 🔗


There are many other state management libraries available for React, and the best one for your application will depend on your specific needs and requirements. It’s important to carefully evaluate the different options and choose the one that best fits your needs.

Feel free to mention some worthy 👌🏻 state management libraries you can vouch for on the comments section below. 👇🏻

There's more to read!

ArticleEcommerce

Online Grocery Shopping Apps in the Philippines (2022 Edition)

•  4 min read
ArticleCybersecurity

Top 5 VPN Providers in the Philippines

•  6 min read
Everything Else.
HomeBlogProjects
Works
WebsitesLanding PagesPrintSoftware
Link to $https://github.com/gianfayeLink to $https://www.linkedin.com/gianfaye/Link to $https://twitter.com/gianfayeLink to $https://stackexchange.com/users/2642726/gian-faye?tab=accountsLink to $mailto:contact@gianfaye.com

© 2022 Gian Faye Paguirigan

PrivacyTerms of UseRSS