How to manage state in a React app using Redux.
Tags: redux, webdev, javascript, tutorial
Published: 2023-09-15 23:36:54

In this tutorial, you will manage the state of a React app using Redux. Redux helps you track and manage the state of an entire application in a single object instead of having the state and logic in a top-level component.

You will build a to-do app that centralizes the state and logic using Redux.

By the end of the tutorials you will know:

* What Redux is and the benefit of using Redux for state management.
    
* Understand and use Redux concepts such as the store, reducer, actions, etc. in a Todo app.
    

The tutorial will be in two sections. The first section explains key concepts, the Redux architecture, and the basic usage of Redux. In the next section, we will build a Todo app using Redux for state management.

## Prerequisite

To get the most out of this tutorial you should be familiar with:

* Functions in JavaScript
    
* Knowledge of React terminology: State, JSX, Components, Props, and Hooks
    
* Building a basic React app
    

## Introduction to State Management

React enables developers to build complex user interfaces easily. To add interactivity to the UI, React components need access to data. The data can be a response from an API endpoint or defined within the app. This data will be updated in response to an interaction, such as when a user clicks on a button, or types into an input field.

Inside a React component, the data is stored in an `object` called `state`. Whenever `state` changes, the component will re-render, and React will update the screen to display the new data as part of the UI.

In a React app, multiple components may need access to the state. Hence, it needs to be effectively managed. **Effective state management entails being able to store and update data in an application.**

## What is Redux?

> **Redux is a pattern and library for managing and updating application state, using events called "actions".** It serves as a centralized store for state that needs to be used across your entire application, with rules ensuring that the state can only be updated in a predictable fashion.

With Redux, you have a central store to keep, update, and monitor the state of your application. That means, our components may not have states. The state will be in a central location and can be accessed by multiple components in your application.

## What problem does Redux solve?

A basic React app can be segmented into the following:

* **State**: The current condition of the app
    
* **View**: The UI of the app
    
* **Actions**: A function that updates the state when an event occurs in your app (generally referred to as Event handlers).
    

Every component in an app can have a state. However, it becomes a challenge if multiple components need access to the same data. To solve this issue, we "lift the state up". Lifting state up is a process where you move the state from a child component to its parent (top-level) component. With this approach, you can easily share state between multiple child components.


![LiftingStateReact](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qog5n8pz08ulzahxoxxi.png)

However, there are disadvantages to "lifting state up":

* **It can complicate your code:** Lifting the state up can add huge boilerplate code to your components. The state must be passed down from the parent component to the child components resulting in `prop-drilling`. Additionally, the state is updated in the parent component.
    
* **It can impact performance:** When you lift the state up, you increase the number of components that will re-render when the state changes. This can affect performance, especially on mobile devices.
    

In a large-scale single-page application, our code will manage more states. This state can include server responses and cached data, as well as locally created data that has not yet been persisted to the server. It will get to the stage where you will lose control over when, why and how the state updates. Making it difficult to reproduce bugs or add new features.

**A better approach is to extract the shared states from the parent component and put them into a centralized location outside the component tree.**

This is a better approach because:

* It eliminates prop drilling.
    
* Regardless of the component position, you can trigger actions from any component inside the parent component, and the state can be modified.
    

**That is the concept behind Redux. It helps developers manage global state (a state that is needed across many parts of our app), and make the state accessible by all components irrespective of how deeply nested they are.**

*The first rule of Redux is that everything that can be modified in your application should be represented in a single object called the* `state` *or the* `state tree.`

There are key terms to know when using Redux. To make it easy to understand these terms we will first consider an analogy for Redux. After this, we will define the terms in the next sections.

### Redux analogy

Imagine you are the Managing Partner of a huge restaurant. To be well versed in managing the restaurant, you decide to **keep track of the state** of the restaurant.

You might want to track:

* The stock of the various ingredients available
    
* Financial status (weekly income and expenditure pattern)
    
* The number of employed chefs
    
* The number of hired waitresses
    
* Weekly customers etc
    

To keep all this information in your brain will be a hassle. Instead, you keep them in a central location called the **store** (`redux store`).

You hire an **attendant** (`reducer`) who is the only person who can **update the store's information.**

There are **shareholders** (`components`) who rely on the state(data) of the restaurant to update their portfolio (`UI`). These **shareholders can only access data and cannot modify it.**

Now let us assume the shareholders hire a new chef and the store's data need to be updated. Because they cannot update the data, a shareholder can send (`dispatch`) a note with that new information to the attendant(`reducer`)**.** He then **updates the previous data in the store with the latest information**.

**Anytime data is updated, the rest of the shareholders are notified (**`subscribers`**), and they can update their portfolio (**`UI`**)**


![ReactRedux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9nd4ia52ddybwjm8y14.jpg)

## Understanding the Redux Terminologies

Below are the new terms to be familiar with:

### Actions

*The second rule of Redux is that the* `state` *is read-only. You can only modify the state tree by sending an* `action`*.* This ensures that neither the views nor the network callbacks will ever write directly to the state. Instead, they express an intent to transform the state.

In other words, `action` is the only recommended way to change the application `state`.

**An action describes what has occurred in the application.** It is a JavaScript object passed as a parameter to the `store` and holds the information required for the `store` to update the `state`.

An `action` varies in any given application. For instance, in a counter app, you will only need the following `actions:`

* increased the count
    
* decreased the count
    

In a todo app, you may have the following `actions`:

* Added todo item
    
* Deleted todo item
    
* Complete todo item
    
* Filter todos, etc.
    

With Redux, because we are separating the `state` from the components, the components don't know exactly how the state changes. All they care about is that they need to send an `action`.

The action `object` has a `type` property where you specify what event occurred in your component. That means whenever an event occurs, the event handler function will dispatch an `action` with what has occurred to help update the `state` in the store.

The `action` `object` also has a `payload` property. Any new data about the event will be in the `payload`. For instance, when I dispatch an `action` of `type` "addedTodo", the `payload` can contain the **new to-do item and the ID.**

Below are examples of `action` objects:

```javascript

//action 1
const addTodoAction = {
  type: 'todos/todoAdded', //what happened
  payload: {todoID, newTodo} //data
}
//action 2
const getOrder = {
type: 'orders/getOrderStatus', //what happened
payload: {orderId, userID} //data
}
```

### Action Creators

The `action creators` are functions that return `action` objects. Because the `action creators` contains the logic that can be used in multiple instances of the application, you can pass it some `parameters` that can be accessed in the `action` objects.

Below are examples of `action creators`:

```javascript
//example 1
function addTodo(todo){
//return action object
return {
  type: 'todos/addTodo',
  payload: todo // what happened
    }
}
//example 2
function getOrders(orderID, userID){
//return action object
  return {
       type: 'orders/getOrderStatus',
       payload: {orderId, userID} //what happened
   }
}
```

### Reducers

A `reducer` is a **pure function** that accepts the current `state` and an `action` as `arguments` and returns the updated `state`. It is called a `reducer` because similar to the `Array.reduce()` method, the Redux reducer **reduces a set of actions over time into a single state.**

The reducer should be a pure function. A pure function is a function that will return the same output for the same input. **It does not change or modify the global state or the state of any other functions.**

What this means is :

* A reducer function is not allowed to modify the current `state`. Instead, they must make a copy of the current `state` and update the copied values.
    
* A reducer function should not update the state by reading from a database
    
* A reducer function should not make a call to any third-party API
    

Below is the syntax of a reducer function:

```javascript
const myReducer = (state, action) => newState
```

The logic inside the reducer function is as below:

* In the body of the function, we check the `action.type` property.
    
* If the `type` of action matches something you have defined, you will make a copy of the `state`, and modify that state with the new value from the `action.payload`
    
* If the `action.type` does not match anything you have defined, you will return the existing `state`
    

Below is an example of a `todoReducer` function:

```javascript
const intialTodo = [{id:1, todo:""}]

const todoReducer = (state = initialTodo, action)=>{
if(action.type === "todos/AddedTodo"){
  return [...state, todo: action.payload]
}else{
return state
 }
}
```

Below is what is happening:

* In the `if` statement verify if the `action.type` matches the expression on the right (`action.type === "todos/AddedTodo"`)
    
* If it does, then we use the spread operator (`...`) to make a copy of the `state` , and update the copy with the new todo data derived from `action.payload`
    
* If not, we return the previous `state`
    

*The third principle of Redux is that to describe state changes, you declare a function that accepts the previous state of the app, the action being dispatched, and returns the next state of the app*

### Store

A `store` in an object that holds the entire `state` of your application. It is the central location of data and where data is updated.

The `store` has three main methods:

* `getState()`: Returns the current `state` of the application
    
* `dispatch(action)`: This is how to instruct the component to send an action to the store to change the `state` of the application.
    
* `subscribe(listener)`: The `subscribe` method will allow the components to listen for a change in data. It accepts a `listener` as a `callback` function that helps you:
    
    * Update the UI to reflect the current state
        
    * Perform side effects or any other task that needs to be done when the state changes.
        

Below is an example of how to create a `store` in redux.

```javascript
//store.js

//import your root reducer
import rootReducer from "./rootReducer"
//import createStore from redux
import {createStore} from "redux"

//create the store
const store =createStore(rootReducer)
```

### Dispatch

Dispatch is used to send `action` to our `store` . It is the only way to change the `state` of our app.

To update the `state` , you will call the `store.dispatch()` method. When `dispatch()` is called, the store will execute the reducers (the reducers have access to the current `state` and an `action` as input, and perform some logic). The store then updates its state with the output of the reducers.

The `store.dispatch()` method accepts the `action` object as an argument.

```javascript
store.dispatch({ type: 'todo/addedTodo' })
```

In the snippet above, for instance, whenever a user enters a new to-do, you will dispatch the action to the `store`. Because there is a `reducer` function inside the store, it will use the dispatched `action.type` to determine the logic for the new state.

### Selectors

Selectors are functions that help you extract specific data from the `state`. It accepts the `state` as an argument and returns the data to retrieve from the `state`.

You will use the `selector` in your component to get specific data from the state.

```javascript
const selectLatestTodo = state => state.data //selector function

const currentValue = selectLastestTodo(store.getState())
console.log(currentValue)
// Buy milk
```

### Illustration of the Redux architechture

In this section, we will use all the terminologies learned to explain how data flow in our app, and how the UI is re-rendered when the state changes.

Let's take a look at the setup of Redux:

* Create a redux `store`
    
* Define the `reducer` logic and pass the `reducer` function to the store. The `reducer` accepts the `state` and `action` object as arguments.
    
* The `store` will run the logic in the `reducer` function
    
* The value returned by the reducer function becomes the initial state of the app.
    
* When the component is mounted, it connects with the store, gets the initial state, and uses the state to display the UI. Because the component is connected to the store, it will have access to any state update.
    

**Updating the state:**

* An event occurs in the app. For instance, a to-do item has been added
    
* The component dispatches the `action` to the redux `store`
    
* The `store` re-runs the `reducer` function. It has access to the previous `state`, the `action` object, and returns the **updated state**
    
* The `store` **notifies** all the connected components of the state change.
    
* Each UI component will verify if it needs to use the updated state.
    
* If it does, it re-renders the UI with the **new state and updates what is on the screen.**
    

![ReduxArchi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp91283ar3ttoxlbr1uq.jpeg)


## Creating a `store`, `subscribing` and dispatching `actions`

In this section, we will learn how to create a `store` and `dispatch` actions to the store.

The Redux store brings together the `state`, `reducer` and `action` of our application. It is the central location of the application's state.

The functions of the `store` are to:

* Hold the current state of the application.
    
* Allow access to the current state
    
* Allow the state to be updated
    
* Dispatch actions
    
* Subscribe to changes
    

### Creating a store

Use the `createStore()` method from the Redux library to create the `store`. This method accepts a `reducer` function as an argument.

Below is a code snippet on how to create a store:

```javascript
//store.js
import { createStore} from 'redux'

const store  = createStore(rootReducer)
```

Next, you will need to pass the "root reducer" function to the `createStore()`. The root reducer combines all of the other reducers in your application.

To create a root reducer, you import the `combineReducer()` method from the Redux library. The `combineReducer` helps you combine all the different reducer functions. It accepts an `object` of reducer functions as its argument. The `key` of the object will become the keys in your root state object, and the values are the reducer functions.

Below is an example of how to create a `rootReducer` :

```javascript
import { combineReducers } from 'redux';

const reducers = {
  user: userReducer,
  cart: cartReducer,
  orders: ordersReducer,
};

const rootReducer = combineReducers(reducers);
```

Now, you have learned how to

* Create a store
    
* Add a root reducer to the store
    

Next, you will learn how to get the initial state of the store and dispatch actions to the store

### Dispatching `actions` to the `store`

To update the `state` of the application, the component needs to dispatch actions.

Below is how to do that:

* Import the `store` into your application
    
* call the `store.dispatch()` methods and pass it the `action` objects.
    

```javascript
//actions object
const addTodo = {
  type: 'todos/todoAdded',
  payload: "Buy milk"
});

const completeTodo = {
  type: 'todos/todoRemoved',
  payload: 2 // id of the todo to complete
}
//dispatch the action to update the state 
store.dispatch(addTodo)
store.dispatch(completeTodo)
```

### Subscribing to the store

Use the `subscribe()` method to subscribe to a store. The `subscribe()` method will listen for changes to the `state` of your app. This will help you update the UI to reflect the current `state`, perform side effects, or any task that needs to be done when the `state` changes.

In the code snippet below illustrates how to listen for updates, and log the latest state to the console:

```javascript
const subscription = store.subscribe(() => {
  // Do something when the state changes.
  console.log('State after dispatch: ', store.getState())
});
```

## Adding Redux to a React app

In this section, you will use the concept learned to build a to-do app with basic functionalities ( add, delete, and complete a todo) while using redux for `state` management.

We will not go in-depth into each implementation as we have covered the concepts earlier.

Here are the steps to follow:

1. Set up your React project and install the required dependencies
    
2. Create your Todo components for the UI
    
3. Create a redux `store` to track and manage the `state` of your app
    
4. Define the `reducer` logic and connect to the store
    
5. Dispatch `actions` to update the `state`
    
6. Read data from the `store`
    

The repository for the project is found [here](https://github.com/emmanuelkumah/react-redux-tut). It has branches for each major step we will implement.

Let's get started

### Step 1: Setting up your project

Create a React app in your project directory by following the steps below:

* Start a project from the basic template using Vite by running the command below in your terminal:
    
    ```javascript
    npm create vite@latest my-react-app --template react
    // Replace "my-react-app" with the name of your project.
    ```
    
* Install the `redux` and `react-redux` dependencies in your `package.json` file. Run the command
    
    ```javascript
    npm install redux react-redux --save
    ```
    
    This installs the core redux architecture and simplifies connecting the react app with redux.
    
* Run the app with `npm run dev`
    

### Step 2: Creating the Todo components

Below is the UI for our app.


![TodoRedux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rn2ky9r2ifulkth66uge.png)

Now, let's create the required components

* Create a "components" folder in the "src" directory
    
* The components needed to create the UI of the app are:
    
    * `<TodoHeading/>` : contains the heading text
        
    * `<TodoInput/>` : an input to enter a todo
        
    * `<TodoItem/>` : displays a single todo, with a delete and complete button
        
    * `<TodoList/>` : display the lists of todos.
        


![Components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fndmur9g04vyff7n3876.png)

### Step 3: Creating the `store`

Next, we will need to create a `store` to keep track of and manage the entire `state` of the application. We do that using the `createStore()` method from Redux.

Follow these steps:

* Create a "store" folder in the root directory of your app
    
* Create a `store.js` file inside the "store" folder
    
* Import the `createStore` method from redux
    
* Call the `createStore()` method, and pass the `todoReducer` as an argument ( we will define this in the next step)
    
* Export the `store` to be used inside your React app
    

```javascript
//store/store.js
import { createStore } from "redux";
import todoReducer from "../reducer/todoReducer";

const store = createStore(todoReducer);

export default store;
```

### Step 4: Defining the `reducer` function

We will define our reducer inside a `todoReducer.js` file. Reducers are functions that contain the logic required to update the state and return a new state. The `todoReducer.js` will also contain the initial state of our app.

Follow the steps below to define a `reducer` function:

* Create a `todoReducer.js` insider a "reducer" folder
    

Add the code snippet below to the file

```javascript
//state object
const initialState = {
  todos: [
    {
      id: 1,
      item: "Learn redux fundamentals",
      completed: false,
    },
    {
      id: 2,
      item: "Build a todo-app",
      completed: false,
    },
  ],
};

//define the reducer logic
const todoReducer = (state = initialState, action) => {
  switch (action.type) {
//logic to add a new todo
    case "todos/addedTodo":
      return {
        ...state,
        todos: [...state.todos, action.payload],
      };
//logic to delete a todo
    case "todos/deleteTodo":
      return {
        ...state,
        todos: state.todos.filter((todo) => todo.id !== action.payload),
      };
// logic to complete a todo
    case "todos/completeTodo":
      return {
        ...state,
        todos: state.todos.map((todo) => {
          if (todo.id === action.payload) {
            return {
              ...todo,
              completed: !todo.completed,
            };
          } else {
            return todo;
          }
        }),
      };
    default:
      return state;
  }
};

export default todoReducer;
```

In the code above:

* We added the initial `state` of our app. It is prefilled with an `array` of todos to enable us to display some dummy data when the app is rendered.
    
* We define the `todoReducer` function. This function accepts the `state` and `action` objects as parameters.
    
* In the body of the function, we implemented a `switch` statement. Based on the expression (`action.type`) there is a logic in each `case` on how the `state` will be updated and returned.
    
* Finallly, we `export` the `todoReducer` and pass it as an argument to the `createStore()` method (as previously indicated).
    

### Step 5: Wrapping the `Provider` component around your app

The `Provider` component enables the Redux `store` to be available to any nested components that need to access the `store`.

Since any React component in a React Redux app can be connected to the store, most applications will render a `Provider` at the top level, with the entire app’s component tree inside of it.

Below is how to wrap our root component inside a `Provider`

* Import the `store` in the `main.jsx`
    
* Import the `Provider` component from "react-redux"
    
* Wrap your root component `<App/>` in the `Provider`
    
* The `Provider` accepts a `store` props with the imported `store` as its value
    

```javascript
//main,jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { Provider } from "react-redux"; //Provider
import store from "./store/store.js"; //store 

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <Provider store={store}> 
      <App />
    </Provider>
  </React.StrictMode>
);
```

In the code above, we have wrapped the `<Provider/>` around `<App/>` component to enable all nested components to access the `store`

Next, we would read and display data from the store using the `useSelector` hook

### Step 6: Reading and displaying the todos with `useSelector` hook

React-Redux has its custom hooks, which you can use in your components. The `useSelector` hook **lets the React components read data from the Redux store**. It accepts a selector function that **takes the entire Redux store state as its argument, reads some value from the state, and returns that result**.

Follow the steps below to read and display data:

* Import the `useSelector` from "react-redux"
    
* Call the `useSelector()` method. It accepts a selector function as a callback
    
* Return the `todos` from the `state`
    

The code below illustrates how to read the `todos` from our store.

```javascript
//components/TodoList.jsx
import React from "react";
import { useSelector } from "react-redux";
import TodoItem from "./TodoItem";

const TodoList = () => {
//callback function
  const selectTodos = (state) => state.todos; 
//extract the todos
  const returnedTodos = useSelector(selectTodos);

  const displayTodos = returnedTodos.map((todo) => (
    <TodoItem key={todo.id} todo={todo} />
  ));
  return <div>{displayTodos}</div>;
};

export default TodoList;
```

Let's understand the code above:

* The first time the `<TodoList/>` component renders, the `useSelector` hook will execute the `selectTodos` callback function.
    
* What is returned by the `selectTodos` will be returned by the `useSelector` hook to be used in our component.
    
* The `const returnedTodos` will hold the same data as the `state.todos` inside our Redux store state.
    
* We use the JavaScript `map()` method to iterate over each todo and display a single todo.
    
* The `useSelector` **automatically subscribes** to the Redux store. Hence, whenever an `action` is dispatched, it will call the `selectTodos`function. **If the value returned by the** `selectTodos` **has been updated,** `useSelector` **will force the** `TodoList` **component to re-render with the new data.**
    

We know how to read and display data from the `store`. Next, we will learn how to dispatch actions from the components to update the store

### Step 5: Dispatching actions with `useDispatch` hook

The `useDispatch` hook provides access to the `dispatch` method that is needed to dispatch `actions` to update the `state`.

We can call `const dispatch = useDispatch()` in any component that needs to dispatch actions, and then call `dispatch(someAction)` as needed.

In the `TodoInput` component, let's dispatch an action to add a new todo:

* import `useDispatch` from "react-redux"
    
* Call the `useDispatch()` method. It returns the `dispatch` function
    
* Enter and submit the new todo
    
* Call the `dipatch()` method in the `addTodo` and pass the `action` object
    
    ```javascript
    //components/TodoInput.jsx
    import React, { useState } from "react";
    import { useDispatch } from "react-redux";
    
    const TodoInput = () => {
      const [todo, setTodo] = useState("");
      const dispatch = useDispatch();
    
      const onInputTodo = (e) => {
        setTodo(e.target.value);
      };
      //handle submission of todo
      const handleTodoSubmit = (e) => {
        e.preventDefault();
        addTodo(); // addTodo 
        setTodo("");
      };
    //action creators
      const addTodo = () => {
    //dispatch action to add a todo
        return dispatch({
          type: "todos/addedTodo",
          payload: { id: Math.floor(Math.random() * 20) + 1.1, item: todo },
        });
      };
      return (
        <div>
          <form className="todo_form_container" onSubmit={handleTodoSubmit}>
            <input
              className="todo_input"
              type="text"
              placeholder="Enter your todo"
              value={todo}
              onChange={onInputTodo}
            />
            <button className="todo_btn">Add Todo</button>
          </form>
        </div>
      );
    };
    
    export default TodoInput;
    ```
    

In the code above, on submitting a new todo:

* The `handleTodoSubmit` function executes the `addTodo()` function
    
* The `addTodo()` dispatches the `action` object to the `todoReducer` function to update the `state`
    

Because we have imported the `useSelector` hook, we can easily add a new todo to the store's state, and it will reflect in the UI.

<img width="100%" style="width:100%" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMW1kMW5zbjJvNzBwOTV6d2I1aGozcWc3c3BwN3hweWEzZzhsZ25kZSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/2AvGJrj8po5PKFbK6T/giphy.gif">



Below is what we have done so far

* Create the `store`
    
* Wrap the `<Provider store={store}>` around your top-level `<App>` component to enable all other components to access and update the store.
    
* Call the `useSelector` hook to read data in React components
    
* Call the `useDispatch` hook to dispatch actions in React components
    

### Dispatching action on clicking the "delete" and "complete" buttons

In the `TodoItem` components, we can now click on the "delete" and "complete" button. On clicking these buttons we dispatch actions to delete and complete a todo. These are handled in the `onDelete` and `onComplete` action creators.

The code snippet is as below:

```javascript
//components/TodoItem.jsx
import { useDispatch } from "react-redux";

const TodoItem = ({ todo }) => {
  const dispatch = useDispatch();
  //delete a todo
  const onDelete = (id) => {
    return dispatch({
      type: "todos/deleteTodo",
      payload: id,
    });
  };
  //complete Todo
  const onComplete = (id) => {
    return dispatch({
      type: "todos/completeTodo",
      payload: id,
    });
  };
  return (
    <div>
      <h3 className={`todo${todo.completed ? "Completed" : ""}`}>
        {todo.item}
      </h3>
      <div>
        <button onClick={() => onComplete(todo.id)}>Complete</button>
        <button onClick={() => onDelete(todo.id)}>Delete</button>
      </div>
    </div>
  );
};

export default TodoItem;
```

* Clicking the "delete" and "complete" button calls the `onDelete()` and `onComplete` functions respectively. The `onDelete` function dispatches an action to the `todoReducer` to delete the specified item while the `onComplete` function dispatches an action to the `todoReducer` to complete the selected item.

<img width="100%" style="width:100%" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExaGU5NXc2M2l0Z3Q3ajVpemw1ZmV5bHRiZzh0cGJucm05czQ4YzU2eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3NyLtnjTAPf5Sj68YZ/giphy.gif">
    



## Redux vs Context API

The difference between Redux and Context API is how they manage states. In Redux state is managed in a central store. However, the Context API deals with state updates on a component level, as they happen within each component.

You might ask, can't you use the `useContext` hook from the Context API to pass state to multiple components since that eliminates `prop drilling`?

In a scenario where a state affects multiple components or is required by all the components in an app, you can use the `useContext` hook to manage `state`. This avoids props drilling and makes data easily accessible in all components.

However, there are some disadvantages to using `useContext`:

* The `useContext` hook has a complex setup: When building an enterprise-level app where multiple components may need access to `state`, you might have to use the `context` API to create multiple contexts and provide each context with the data required for the different aspects of your application. For instance, you will create
    
    * Authentication Context: to easily authenticate users
        
    * Theming Context: to change the theme. For example, enable dark mode
        
    * Form Context: to pass form data to the form component, etc.
        
    
    This phenomenon might result in having to create multiple contexts to meet a specific need, leading to deeply nested Context Provider components in your application.

![context](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ar6hgysdzmfq0l5bc96o.png)
    
* Secondly, `useContext` is not optimized for enterprise-level apps where the state changes frequently. This will decrease the performance of your app.
    
* Lastly, when using `useContext`, UI logic and state management will be in the same component.
    

Below are some scenarios you might use Redux over `useContext`:

* There are lots of states in your application, and these states are required in many places in the app.
    
* The app state is updated frequently over time
    
* The logic to update that state may be complex
    
* The app has a medium or large-sized codebase and might be worked on by multiple developers
    

## Conclusion

In this tutorial, you managed the state of a React Todo app using Redux. Next, learn how to manage the state using the [Redux Toolkit](https://redux-toolkit.js.org/). Redux Toolkit makes it easier to write good Redux applications and speeds up development. Furthermore, learn Redux DevTools to help you trace when, where, why, and how your application's state changed.