How to Add Redux to a React.js Project

2025-08-22 — By Akshay · 8 min read read

Share this article:

How to Add Redux to a React.js Project (Step-by-Step Guide)

State management is one of the most common challenges in React applications. As your app grows, you often need a centralized store where multiple components can access and update shared data. This is where Redux comes into play.

In this guide, we will walk through how to add Redux Toolkit (with Redux Toolkit and Redux Persist) into a React.js application — step by step.


🔹 What is Redux?

Redux is a state management tool that helps you manage global state in predictable ways. Instead of passing props through multiple levels of components, Redux provides:

  • A central store for all application state.
  • Reducers that define how state updates.
  • Actions that describe what happened.
  • Middleware for handling async logic and side effects.

With Redux Toolkit, the setup becomes much simpler compared to the old boilerplate-heavy Redux.


🔹 Setting up Redux in a React Project

Let’s assume you already have a React project set up (using Vite or Create React App). We’ll integrate Redux step by step.

1. Install Dependencies

npm install @reduxjs/toolkit react-redux redux-persist redux-logger

2. Folder Structure

A clean folder structure helps scale your app:

src/
  redux/
    store.js
    rootReducer.js
    features/
      auth/
        slice.js
      todos/
        slice.js
  • store.js → Configures Redux store.
  • rootReducer.js → Combines all feature slices.
  • features/ → Each domain (auth, todos, users, etc.) has its own slice.

3. Create a Slice

Each feature has its own slice using Redux Toolkit’s createSlice.

Example: features/todos/slice.js

import { createSlice } from "@reduxjs/toolkit";

const todoSlice = createSlice({
  name: "todos",
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      state.push({ id: Date.now(), text: action.payload, completed: false });
    },
    toggleTodo: (state, action) => {
      const todo = state.find((t) => t.id === action.payload);
      if (todo) todo.completed = !todo.completed;
    },
    removeTodo: (state, action) => {
      return state.filter((t) => t.id !== action.payload);
    },
  },
});

export const { addTodo, toggleTodo, removeTodo } = todoSlice.actions;
export default todoSlice.reducer;

4. Combine Reducers

Example: redux/rootReducer.js

import { combineReducers } from "redux";
import todoReducer from "./features/todos/slice";
import authReducer from "./features/auth/slice";

const rootReducer = combineReducers({
  todos: todoReducer,
  auth: authReducer,
});

export default rootReducer;

5. Configure Store with Persist

Example: redux/store.js

import { configureStore } from "@reduxjs/toolkit";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import logger from "redux-logger";
import rootReducer from "./rootReducer";

// Persist config
const persistConfig = {
  key: "root",
  storage,
};

// Create persisted reducer
const persistedReducer = persistReducer(persistConfig, rootReducer);

// Configure store
export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({ serializableCheck: false }).concat(logger),
});

export const persistor = persistStore(store);

6. Provide Store to React

Wrap your app with Provider and PersistGate so Redux is available globally.

Example: src/App.js

import React from "react";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./redux/store";
import TodoApp from "./components/TodoApp";

function App() {
  return (
    <Provider store={store}>
      <PersistGate loading={<div>Loading...</div>} persistor={persistor}>
        <TodoApp />
      </PersistGate>
    </Provider>
  );
}

export default App;

7. Using Redux in Components

Now you can use hooks like useSelector and useDispatch to read and update state.

Example: components/TodoApp.js

import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addTodo, toggleTodo, removeTodo } from "../redux/features/todos/slice";

export default function TodoApp() {
  const [input, setInput] = useState("");
  const todos = useSelector((state) => state.todos);
  const dispatch = useDispatch();

  return (
    <div>
      <h2>Todo App</h2>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button
        onClick={() => {
          dispatch(addTodo(input));
          setInput("");
        }}
      >
        Add
      </button>

      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>
            <span
              style={{
                textDecoration: todo.completed ? "line-through" : "none",
              }}
              onClick={() => dispatch(toggleTodo(todo.id))}
            >
              {todo.text}
            </span>
            <button onClick={() => dispatch(removeTodo(todo.id))}>❌</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

🔹 Why Use Redux Persist?

Normally, Redux state resets when the page reloads. Redux Persist saves the store in localStorage (or another storage engine), so your data stays even after refresh.

Use cases:

  • Keep users logged in.
  • Save form data temporarily.
  • Store app preferences (dark mode, language, etc.).

🔹 Final Thoughts

Redux may seem complex at first, but with Redux Toolkit, setting it up is much easier. By combining it with Redux Persist, you ensure that your app maintains state across sessions.

👉 For small apps, React Context might be enough. But if your app grows with authentication, multiple entities, caching, or complex workflows, Redux is still the most reliable choice.


NTheDailyDevs
TheDailyDevs is a developer-first blog and knowledge hub created by passionate engineers to share real-world development tips, deep-dive tutorials, industry insights, and hands-on solutions to everyday coding challenges. Whether you're building apps, exploring new frameworks, or leveling up your dev game, you'll find practical, no-fluff content here, updated daily.