Redux Toolkit & Slices in React – Simplified State Management (2025 Guide)

Redux is powerful, but it involves boilerplate code: defining actions, action types, reducers, and dispatching manually.

Redux Toolkit (RTK) is the official, recommended approach for writing Redux logic in modern React apps.

Redux Toolkit simplifies Redux by reducing boilerplate and providing a structured way to manage state.

Key Benefits:

  • Less boilerplate (no separate action creators or switch statements)

  • Built-in support for immutable state updates using Immer

  • Simplifies async logic with createAsyncThunk

What is a Slice?

A slice is a single unit of Redux logic for a particular piece of state. It contains:

  • Initial state

  • Reducers (functions to update state)

  • Actions (automatically generated)

RTK combines actions and reducers into one place.

Example: Counter Slice

// counterSlice.js
import { createSlice } from "@reduxjs/toolkit";

export const counterSlice = createSlice({
  name: "counter",
  initialState: { count: 0 },
  reducers: {
    increment: (state) => {
      state.count += 1; // Immer allows direct state mutation
    },
    decrement: (state) => {
      state.count -= 1;
    },
    reset: (state) => {
      state.count = 0;
    },
    incrementByAmount: (state, action) => {
      state.count += action.payload;
    },
  },
});

// Export actions automatically generated
export const { increment, decrement, reset, incrementByAmount } = counterSlice.actions;

// Export reducer for store
export default counterSlice.reducer;

Notice how actions and reducers are combined — no separate files needed.

Configuring Store with Redux Toolkit

// store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});
  • configureStore automatically sets up:

    • Redux DevTools

    • Middleware like redux-thunk

  • Makes store configuration simpler and safer

Using Redux Toolkit in React

import React from "react";
import ReactDOM from "react-dom";
import { Provider, useDispatch, useSelector } from "react-redux";
import { store } from "./store";
import { increment, decrement, reset, incrementByAmount } from "./counterSlice";

function Counter() {
  const count = useSelector((state) => state.counter.count);
  const dispatch = useDispatch();

  return (
    <div style={{ textAlign: "center" }}>
      <h2>Count: {count}</h2>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
      <button onClick={() => dispatch(reset())}>Reset</button>
      <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
    </div>
  );
}

ReactDOM.render(
  <Provider store={store}>
    <Counter />
  </Provider>,
  document.getElementById("root")
);

Using Redux Toolkit, updating state is clean and readable.

Async Logic with createAsyncThunk

For API calls, Redux Toolkit provides createAsyncThunk:

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

export const fetchUsers = createAsyncThunk(
  "users/fetchUsers",
  async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    return response.json();
  }
);

const usersSlice = createSlice({
  name: "users",
  initialState: { list: [], status: "idle" },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.status = "loading";
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.list = action.payload;
      })
      .addCase(fetchUsers.rejected, (state) => {
        state.status = "failed";
      });
  },
});

export default usersSlice.reducer;
  • Automatically handles pending, fulfilled, and rejected states

  • Makes async state management clean and predictable

Key Advantages of Redux Toolkit

FeatureBenefit
createSliceCombines actions and reducers, reduces boilerplate
configureStoreAuto configures DevTools and middleware
ImmerAllows safe direct state mutation
createAsyncThunkSimplifies async API calls