Suggest an editImprove this articleRefine the answer for “What does Immer.js do inside Redux Toolkit?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Immer.js** inside Redux Toolkit is responsible for **immutable state updates**. It lets you write code as if you were mutating an object, but it **actually creates a new, unchanged state** using a **Proxy**. **Key point:** Immer intercepts changes through a "draft" and, once finished, returns a new state tree, copying only the branches that changed.Shown above the full answer for quick recall.Answer (EN)Image## Short answer > **Immer.js** inside Redux Toolkit is responsible for **immutable state updates**. > It lets you **write code as if you were mutating an object**, > but it **actually creates a new, unchanged state** using a **Proxy**. --- ## What happens when you call `createSlice()` When you write a reducer in RTK like this: ```javascript const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment(state) { state.value++ // ← you seem to be mutating }, }, }) ``` RTK **does not store this reducer directly**. Under the hood it wraps your function with Immer: ```javascript import { produce } from 'immer' function wrappedReducer(state, action) { return produce(state, draft => { state.value++ // ← becomes "draft.value++" }) } ``` Immer takes `state`, creates a **"draft"** of it, lets you make changes to it, and once finished returns a **new state**, in which only the needed fields are changed, while everything else stays the same (by reference). --- ## How `produce()` works (the heart of Immer) Here is a minimal implementation of the "magic": ```javascript import { produce } from 'immer' const baseState = { count: 1, user: { name: 'Maria' } } const nextState = produce(baseState, draft => { draft.count++ draft.user.name = 'Alex' }) console.log(nextState) // { count: 2, user: { name: 'Alex' } } console.log(baseState) // { count: 1, user: { name: 'Maria' } } unchanged ``` --- ## What Immer actually does under the hood 1. **Creates a Proxy for the** `state` **object** Every property access (`get`, `set`, `delete`) is intercepted. 2. **Remembers every change you make** Immer does not change the object right away - it records instructions: ```javascript - increment count - change user.name ``` 3. **After exiting** `produce()` Immer creates a **new state tree**, copying only the changed parts. Everything that was not changed stays **at the old references** → this is very memory-efficient. 4. **Returns the new state** The new object is "clean" and immutable - it can safely be passed on into Redux. --- ## Example: nested changes ```javascript const state = { user: { name: 'Maria', age: 25 }, settings: { theme: 'dark' } } const next = produce(state, draft => { draft.user.age = 26 }) ``` Immer: - Creates a new copy of only the `user` branch - `settings` stays **at the same reference** - So `next.settings === state.settings` → `true` This makes updates **very performant**, because only the changed part of the tree gets copied. --- ## How RTK uses Immer internally Redux Toolkit integrates Immer into `createReducer()` and `createSlice()`. Every reducer you declare effectively becomes: ```javascript (state, action) => produce(state, draft => { // your code }) ``` In RTK this happens automatically, so you do not need to call `produce()` explicitly. --- ## Example without RTK (plain Redux) ```javascript function userReducer(state = { name: 'Maria', age: 25 }, action) { switch (action.type) { case 'UPDATE_NAME': return { ...state, name: action.payload } default: return state } } ``` ## Example with RTK (Immer inside) ```javascript const userSlice = createSlice({ name: 'user', initialState: { name: 'Maria', age: 25 }, reducers: { updateName(state, action) { state.name = action.payload // works thanks to Immer } } }) ``` Both do the same thing - only in RTK the code is twice as short, and immutability is guaranteed automatically. --- ## Why this matters | Problem without Immer | What Immer solves | | --- | --- | | You have to copy objects manually (`{ ...state }`) | Does it automatically | | Mutation bugs | Eliminates them | | Hard to update nested structures | You can access it directly (`state.user.name = ...`) | | Slow deep copying | Copies only the changed branches | | A lot of boilerplate | The code becomes natural and short | --- ## Visually (what Immer does) ```javascript [original state] │ ▼ a proxy (draft) is created │ ▼ you "mutate" the draft │ ▼ Immer records the changes │ ▼ returns the new state (immutable) ``` --- ## Summary | What Immer does inside RTK | What it looks like | | --- | --- | | Creates a state "draft" via a Proxy | `draft` | | Lets you mutate the `draft` | `state.value++` | | Tracks all changes | through Proxy traps | | Creates a new state on exit | an immutable copy | | Copies only the changed branches | efficient and fast | | Guarantees state safety | without manual spreads | --- **Summary definition:** > **Immer.js in Redux Toolkit** is an "invisible intermediary" > that turns your "mutating" code into a **clean, immutable state transformation** > with minimal memory changes and maximum safety.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.