Skip to content

immer

Write reducers (and set calls) as Immer draft mutations instead of returning new state objects.

Basic usage

ts
import { withPlugins } from "@kin-store/core";
import { immer } from "@kin-store/plugins";

const store = withPlugins({ count: 0, items: [] as string[] })
  .use(immer({
    reducers: {
      increment(draft, amount: number): void {
        draft.count += amount;
      },
      addItem(draft, item: string): void {
        draft.items.push(item);
      },
    },
    methods: (store) => ({
      reset(): void {
        store.set((draft) => {
          draft.count = 0;
          draft.items = [];
        });
      },
    }),
  }));

store.dispatch.increment(5);
store.dispatch.addItem("hello");
store.reset();

The immer() wrapper accepts the same fields as a standard StorePlugin: reducers, middleware, methods, onActivated, and onDestroy. Inside those callbacks, reducers mutate a draft instead of returning a new object, and set accepts a recipe (draft) => void instead of a full state replacement.

With namespacing

immer can also be applied as a namespaced plugin:

ts
const store = withPlugins({ todos: [] as string[] })
  .use(
    "todos",
    immer({
      reducers: {
        add: (draft, text: string) => {
          draft.todos.push(text);
        },
        clear: (draft) => {
          draft.todos = [];
        },
      },
    }),
  );

store.dispatch.todos.add("hello");
store.dispatch.todos.clear();

Note on type inference

Because Immer mutates a draft in-place (void return), reducers written with immer do not need to return a value. TypeScript fully infers argument types from the reducer signature.

Released under the MIT License