jotai-immer
Immer-powered draft mutations for Jotai atoms, with drop-in atom creators and hooks.
Repository Health
Technical Analysis
jotai-immer is a small integration library that lets Jotai atoms be updated with Immer’s mutable draft syntax instead of hand-written immutable spread logic. It ships four building blocks — atomWithImmer, withImmer, useImmerAtom, and useSetImmerAtom — covering both atom-creation and atom-wrapping styles, plus React hooks for components that prefer to work with an existing writable atom.
Under the hood every setter runs the atom’s current value through Immer’s produce, so updates read like plain object or array mutations (draft.count += 1) while Jotai still receives an immutable next value. Setting a value to undefined resolves to Immer’s nothing sentinel, correctly resetting the atom instead of being ignored.
What You Get
- atomWithImmer(initialValue) — a writable atom whose setter accepts either a full value or an Immer draft-mutation function
- withImmer(anAtom) — wraps an existing writable atom so its setter gains Immer draft semantics without redefining the atom
- useImmerAtom(anAtom) — a useAtom-style hook returning [value, setDraft] for atoms with Immer setters
- useSetImmerAtom(anAtom) — a useSetAtom-style hook for write-only access with Immer draft mutations
- Full TypeScript types covering both single-value and multi-arg atom setter signatures
Common Use Cases
- Managing deeply nested form or settings state where spread-based immutable updates would be verbose
- Migrating a Redux/Immer-based reducer pattern to Jotai without rewriting update logic into spreads
- Building collection state (todo lists, tables, trees) where items are pushed, removed, or edited by index
- Wrapping a derived/writable atom from another Jotai utility library so its setter also accepts draft mutations
Under The Hood
Architecture The library exposes four files re-exported via index.ts. atomWithImmer creates a self-referential writable atom whose write function calls Immer’s produce on the atom’s own current value, then writes the result back through Jotai’s low-level atom() from ‘jotai/vanilla’. withImmer takes an arbitrary existing writable atom and wraps it in a derived atom using the same produce-based logic, so the pattern also works when you don’t own the original atom’s creation; a WeakMap-based memo1 cache keyed by the wrapped atom instance ensures calling withImmer(anAtom) repeatedly returns the same derived atom rather than creating duplicates on every render. useImmerAtom and useSetImmerAtom are thin React hooks layered on jotai/react’s useAtomValue and useSetAtom — useSetImmerAtom wraps the setter in Immer’s produce(fn) curried form and memoizes it with useCallback, while useImmerAtom composes useAtomValue and useSetImmerAtom into the familiar [value, setter] tuple. Data flow is unidirectional and synchronous: draft mutation callback → produce() computes the next immutable value → set() writes it into the underlying Jotai atom → subscribers re-render.
Tech Stack Peer dependencies are immer >=9.0.0 and jotai >=2.0.0; devDependencies use React 19, TypeScript 6, Vite 8, Vitest 4, and ESLint 9’s flat config with Prettier for formatting. The build produces dual ESM/CJS output via two dedicated tsconfig files (tsconfig.esm.json, tsconfig.cjs.json) compiled with tsc, with a conditional exports map in package.json providing require/default entry points and a synthesized {“type”:“commonjs”} marker for the CJS output. The repo is a pnpm workspace with four example apps under examples/, each with its own package.json and Vite dev script.
Code Quality Tests exist under tests/ (atomWithImmer.spec.tsx, withImmer.spec.tsx, useImmerAtom.spec.tsx, useSetImmerAtom.spec.tsx) using Vitest, @testing-library/react, and happy-dom, covering both the hook-based path and direct store.set() access, including the undefined-to-nothing reset edge case. Source files are small (20-50 lines each), consistently typed with generics constrained to WritableAtom<Value, Args, Result>, and use .js-suffixed relative imports per the NodeNext ESM convention. There is no explicit error handling because failure modes are delegated to Immer and Jotai themselves; naming is consistent and deliberately mirrors Jotai’s own primitives.
API Design The public surface is deliberately minimal — four exports that mirror Jotai’s own naming conventions (atom/useAtom/useSetAtom → atomWithImmer/useImmerAtom/useSetImmerAtom), so anyone already familiar with Jotai has almost no new API to learn. Overloaded TypeScript signatures on withImmer, useImmerAtom, and useSetImmerAtom give accurate types for both the draft-callback and plain-value setter forms. Getting started requires only swapping atom() for atomWithImmer() or wrapping an existing atom — no provider, configuration, or additional boilerplate.
Used by 2 apps in this directory
agenta
Developer Tools · Devops · AI Development
The open-source LLMOps platform unifying prompt engineering, evaluation, and observability for teams building reliable LLM applications.
APITable
Low Code Platforms · Databases
API-first collaborative spreadsheet-database platform that auto-generates REST APIs and lets teams build internal tools, CRMs, and dashboards without code.