DEV Community

Cover image for React Mastery Series – Day 22: State Management with Redux Toolkit – Building Enterprise React Applications
Siva Samanthapudi
Siva Samanthapudi

Posted on

React Mastery Series – Day 22: State Management with Redux Toolkit – Building Enterprise React Applications

Welcome back to the React Mastery Series!

In the previous article, we explored TypeScript with React and learned how static typing improves code quality, developer productivity, and application reliability.

Today, we're diving into one of the most requested topics in React interviews and one of the most widely used state management solutions in enterprise applications:

Redux Toolkit (RTK)

If you've ever wondered:

  • Why do we need Redux when React already has Context API?
  • What problems does Redux solve?
  • Why is Redux Toolkit preferred over traditional Redux?

This article answers all of those questions.


Why Do We Need Redux?

Imagine you're building an enterprise banking application.

It contains:

  • Login
  • Dashboard
  • Accounts
  • Transactions
  • Beneficiaries
  • Profile
  • Notifications

Many screens need the same data:

  • Logged-in user
  • Authentication token
  • Customer profile
  • Theme
  • Permissions

Without centralized state:

Component A
     |
Component B
     |
Component C
     |
Component D
Enter fullscreen mode Exit fullscreen mode

Each component manages its own copy of the data.

Problems:

  • Duplicate API calls
  • Inconsistent state
  • Difficult debugging
  • Complex data flow

Context API vs Redux

Many developers ask:

"Why not just use Context API?"

Context works well for:

  • Theme
  • Authentication
  • Language
  • User preferences

However, for applications with:

  • Frequent state updates
  • Large datasets
  • Complex business logic
  • Multiple developers

Redux provides better scalability and tooling.

Context API Redux Toolkit
Good for simple shared state Designed for complex state
Basic state sharing Predictable state management
Limited debugging Excellent DevTools support
Minimal boilerplate Simplified with RTK

What is Redux?

Redux is a predictable state management library.

It stores application state in one central location called:

Store

Instead of multiple components managing separate state:

Header

Dashboard

Profile

Sidebar
Enter fullscreen mode Exit fullscreen mode

Everything reads from one source.

          Store
             |
   --------------------------
   |      |       |        |
Header Dashboard Profile Sidebar
Enter fullscreen mode Exit fullscreen mode

Core Redux Concepts

Redux is built around four ideas.

Store
  ↓
Action
  ↓
Reducer
  ↓
Updated State
Enter fullscreen mode Exit fullscreen mode

Let's understand each one.


What is a Store?

The Store is the central container for your application's state.

Example:

Store
├── auth
├── user
├── transactions
├── accounts
└── settings
Enter fullscreen mode Exit fullscreen mode

Every component reads data from the Store.


What is an Action?

An Action describes what happened.

Example:

{
  type: "LOGIN"
}
Enter fullscreen mode Exit fullscreen mode

Another example:

{
  type: "ADD_TRANSACTION",
  payload: {
    amount: 500
  }
}
Enter fullscreen mode Exit fullscreen mode

Notice:

Actions never update state directly.

They simply describe an event.


What is a Reducer?

A Reducer decides how state changes.

Example:

Current State
      +
   Action
      ↓
  New State
Enter fullscreen mode Exit fullscreen mode

Reducers must:

  • Be pure functions
  • Never mutate existing state
  • Always return new state

Traditional Redux vs Redux Toolkit

Older Redux required:

  • Action creators
  • Constants
  • Reducers
  • Store configuration
  • Boilerplate code

Example project:

actions.js
constants.js
reducers.js
store.js
Enter fullscreen mode Exit fullscreen mode

Redux Toolkit removes most of this boilerplate.


Installing Redux Toolkit

npm install @reduxjs/toolkit react-redux
Enter fullscreen mode Exit fullscreen mode

Packages:

  • @reduxjs/toolkit
  • react-redux

These are all you need for most applications.


Creating the Store

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

import authReducer from "./authSlice";

export const store = configureStore({
  reducer: {
    auth: authReducer
  }
});
Enter fullscreen mode Exit fullscreen mode

configureStore() automatically enables useful defaults like Redux DevTools and middleware.


What is a Slice?

A Slice groups:

  • State
  • Reducers
  • Actions

into one file.

Example:

authSlice.ts
├── Initial State
├── Reducers
└── Generated Actions
Enter fullscreen mode Exit fullscreen mode

This is the biggest improvement introduced by Redux Toolkit.


Creating Your First Slice

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

const initialState = { user: null };

const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    login(state, action) {
      state.user = action.payload;
    },
    logout(state) {
      state.user = null;
    }
  }
});

export const { login, logout } = authSlice.actions;
export default authSlice.reducer;
Enter fullscreen mode Exit fullscreen mode

Notice:

We appear to modify state directly.

Redux Toolkit uses Immer internally, so immutable updates happen automatically.


Providing the Store

Wrap the application.

import { Provider } from "react-redux";

<Provider store={store}>
  <App />
</Provider>
Enter fullscreen mode Exit fullscreen mode

Now every component can access Redux state.


Reading State

Use:

useSelector()
Enter fullscreen mode Exit fullscreen mode

Example:

import { useSelector } from "react-redux";

const user = useSelector(state => state.auth.user);
Enter fullscreen mode Exit fullscreen mode

Flow:

   Store
     ↓
useSelector()
     ↓
 Component
Enter fullscreen mode Exit fullscreen mode

Updating State

Use:

useDispatch()
Enter fullscreen mode Exit fullscreen mode

Example:

import { useDispatch } from "react-redux";

const dispatch = useDispatch();

dispatch(login({ id: 1, name: "Siva"}));
Enter fullscreen mode Exit fullscreen mode

Flow:

    Button Click
         ↓
    dispatch()
         ↓
     Reducer
         ↓
   Store Updated
         ↓
Component Re-renders
Enter fullscreen mode Exit fullscreen mode

Enterprise Authentication Flow

Login Form
     ↓
Authentication API
     ↓
dispatch(login())
     ↓
Redux Store
     ↓
Navbar Updates
     ↓
Dashboard Updates
     ↓
Profile Updates
Enter fullscreen mode Exit fullscreen mode

Every component immediately receives the updated user information.


Async API Calls with createAsyncThunk

Most applications fetch data from APIs.

Redux Toolkit provides:

createAsyncThunk()
Enter fullscreen mode Exit fullscreen mode

Example:

export const fetchUsers = createAsyncThunk("users/fetch", async () => {
  const response = await fetch("/api/users");
  return response.json();
});
Enter fullscreen mode Exit fullscreen mode

Redux automatically generates:

  • Pending
  • Fulfilled
  • Rejected

states.


Handling Async States

    API Request
         ↓
     Pending
         ↓
Success OR Failure
Enter fullscreen mode Exit fullscreen mode

Typical state:

{
  users: [],
  loading: false,
  error: null
}
Enter fullscreen mode Exit fullscreen mode

Perfect for enterprise applications.


Folder Structure

A scalable Redux Toolkit project:

src

├── app
│   └── store.ts
│
├── features
│   ├── auth
│   │   └── authSlice.ts
│   │
│   ├── users
│   │   └── userSlice.ts
│   │
│   └── transactions

│       └── transactionSlice.ts
Enter fullscreen mode Exit fullscreen mode

Each feature owns its own Redux logic.


Real-World Banking Example

Imagine a customer logs in.

  Login
     ↓
dispatch(login())
     ↓
Store Updated
     ↓
Header

Sidebar

Dashboard

Profile

Notifications
Enter fullscreen mode Exit fullscreen mode

Every screen instantly reflects the new authentication state.


Redux DevTools

One of Redux's biggest advantages is debugging.

You can inspect:

  • Every action
  • Previous state
  • New state
  • Action payload
  • State history

Example:

    LOGIN
      ↓
FETCH_ACCOUNTS
      ↓
ADD_BENEFICIARY
      ↓
   LOGOUT
Enter fullscreen mode Exit fullscreen mode

This makes debugging much easier than scattered component state.


Common Mistakes

1. Putting Everything in Redux

Not all state belongs in the Store.

Avoid storing:

  • Modal visibility
  • Form input values
  • Tooltip state
  • Local UI toggles

Use useState() for component-specific state.


2. Mutating State Outside Redux Toolkit

Incorrect:

state.user.name = "John";
Enter fullscreen mode Exit fullscreen mode

outside a reducer.

Always update state through Redux actions.


3. Creating One Huge Slice

Avoid:

appSlice
Enter fullscreen mode Exit fullscreen mode

containing:

  • User
  • Products
  • Orders
  • Notifications
  • Theme

Instead:

authSlice

userSlice

transactionSlice

themeSlice
Enter fullscreen mode Exit fullscreen mode

Keep slices focused.


Best Practices

  • Organize Redux by feature.
  • Keep slices small and focused.
  • Use createAsyncThunk() for API requests.
  • Keep UI state local.
  • Use Redux DevTools during development.
  • Prefer Redux Toolkit over traditional Redux.

Key Takeaways

Today, we learned:

✅ Redux provides centralized state management.
✅ Redux Toolkit significantly reduces Redux boilerplate.
✅ A Slice combines state, reducers, and actions.
useSelector() reads data from the Store.
useDispatch() sends actions to update state.
createAsyncThunk() simplifies asynchronous API calls.
✅ Redux Toolkit is the preferred Redux approach for modern React applications.


Coming Next 🚀

In Day 23, we will explore:

API Integration in React – Fetch, Axios, Error Handling & Best Practices

We will learn:

  • Fetch API vs Axios
  • GET, POST, PUT, DELETE requests
  • Request interceptors
  • Response interceptors
  • Authentication tokens
  • Global error handling
  • Loading and retry strategies
  • Enterprise API architecture

By the end of the next article, you'll know how production React applications communicate securely and efficiently with backend services.

Happy Coding! 🚀

Top comments (0)