Redux Toolkit: createSlice & Immer

Eliminate legacy Redux boilerplate and safely write mutating logic using the Immer library.

State Management7 min readConcept 11 of 22

What is createSlice?

createSlice is the standard, modern API for writing Redux logic. It eliminates the traditional Redux boilerplate of manually writing action type constants, action creator functions, and giant switch statements.

You simply provide a name, an initial state, and an object of reducer functions. Redux Toolkit automatically generates the corresponding action creators and action types for you.

The Immer Proxy Magic

In traditional Redux, you must never mutate the state. Updating nested objects required tedious and error-prone spread syntax (e.g., ...state, user: { ...state.user, age: 30 }).

Redux Toolkit solves this by wrapping your state in an **Immer Proxy**. Inside createSlice, you can write code that *looks* like it is mutating the state directly (state.value += 1). Immer intercepts these mutations and safely translates them into a brand new immutable object behind the scenes via a process called structural sharing.

Working with Draft State

The state argument passed to your case reducers is not the raw Redux state. It is a temporary **draft state** managed by Immer.

This draft mirrors the exact structure of your real state tree. You can push to arrays, reassign object properties, and delete keys. Once your reducer finishes executing, Immer processes the recorded mutations and creates the new state tree.

Interactive Immer Lab

Use the top toolbar to dispatch actions. Watch how Redux Toolkit lets you write standard mutating JavaScript syntax while Immer seamlessly outputs a brand new immutable state object under the hood.

Dispatch:
import { createSlice } from '@reduxjs/toolkit'; const slice = createSlice({ name: 'example', initialState: { items: ['Apple'], user: { name: 'Alice' } }, reducers: { // 1. Mutate an array (Proxy intercepts push) pushItem(state, action) {
state.items.push(action.payload);
}, // 2. Reassign a property (Proxy intercepts setter) updateName(state, action) {
state.user.name = action.payload;
}, // 3. Return a new object (Replaces entire state) reset(state) {
return initialState;
} } });
Immer Draft Proxy
Waiting for mutation...
New Immutable State
{
  "items": [
    "Apple"
  ],
  "user": {
    "name": "Alice"
  }
}

Immer wraps the state in a Proxy. Your mutations are recorded and applied to a new immutable copy.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1Which of the following reducers will throw an Immer runtime error?

Remember this

  • createSlice automatically generates action creators and action types based on the reducer names.
  • Immer wraps your state in a Proxy, allowing you to safely write "mutating" code like state.push().
  • The state argument in a case reducer is an Immer draft, not the raw state.
  • You must choose to either mutate the draft OR return a new value. Never do both.

Done with this concept?

Mark it complete to track your progress. No login needed.