# Immer — Immutable State with Mutable Syntax > Immer lets you create the next immutable state by mutating the current one. Write mutating code as if it were normal JS and Immer produces a new immutable object via structural sharing. Built into Redux Toolkit and Zustand. ## Install Save in your project root: ## Quick Use ```bash npm i immer ``` ```ts import { produce } from "immer"; const state = { users: [ { id: 1, name: "Alice", tags: ["admin"] }, { id: 2, name: "Bob", tags: ["user"] }, ], }; const nextState = produce(state, (draft) => { draft.users[0].tags.push("verified"); draft.users.push({ id: 3, name: "Carol", tags: ["user"] }); }); // state is unchanged, nextState has the updates console.log(state.users.length); // 2 console.log(nextState.users.length); // 3 console.log(state === nextState); // false ``` ## Intro Immer is a tiny library that makes working with immutable state easy. Instead of writing verbose spread/concat code, you write mutating code against a draft and Immer produces a new immutable state via structural sharing. Created by Michel Weststrate (also creator of MobX), now the backbone of Redux Toolkit, Zustand, and many state libraries. - **Repo**: https://github.com/immerjs/immer - **Stars**: 28K+ - **License**: MIT ## What Immer Does - **produce** — take state + recipe, return new state - **Structural sharing** — only changed paths are copied - **Freeze** — returned state is deeply frozen in dev - **Patches** — capture the diff for undo/redo or sync - **Curried produce** — `produce(recipe)` returns a reducer - **setAutoFreeze** — disable freezing in production for speed - **castDraft / castImmutable** — TypeScript helpers ## Architecture Proxy-based draft: when you access or modify the draft, Immer lazily clones the touched path and tracks mutations. On commit, a new tree is built. Untouched subtrees are shared (structural sharing), so the new state is memory-efficient. ## Self-Hosting Library ships with your app. ## Key Features - Write mutating code, get immutable result - Structural sharing (memory efficient) - Deep freezing in dev - Patch-based diffs (undo/redo) - Curried produce for reducers - TypeScript types - Tiny (~3KB gzipped) - Used by Redux Toolkit, Zustand, Valtio ## Comparison | Approach | Syntax | Memory | Type Safety | |---|---|---|---| | Immer | Mutating draft | Structural sharing | Yes | | Manual spread | Verbose | Manual | Yes | | Immutable.js | Own types | OK | Wrapped types | | Seamless-immutable | Light | OK | Limited | | Mori | Clojure-like | Persistent | Limited | ## 常见问题 FAQ **Q: 性能开销?** A: Proxy 有少量开销,但结构共享节省内存。大部分应用感受不到。Hot path 可以关 autoFreeze。 **Q: 和 Redux 关系?** A: Redux Toolkit 的 `createSlice` 内部用 Immer。这就是为什么你在 reducer 里可以直接 `state.value += 1`。 **Q: 支持 Map/Set 吗?** A: 支持。需要 `enableMapSet()`。v10+ 默认启用常见 ES 集合类型。 ## 来源与致谢 Sources - Docs: https://immerjs.github.io/immer - GitHub: https://github.com/immerjs/immer - License: MIT --- Source: https://tokrepo.com/en/workflows/3ae90d2f-35aa-11f1-9bc6-00163e2b0d79 Author: AI Open Source