30% offEnding soon
All questions

createZustandStore

Premium

createZustandStore

A Zustand-style factory creates one external state snapshot, lets an initializer define actions with set and get, and returns a React hook carrying the same vanilla store API. Implement createZustandStore(initializer) without a Provider. This question focuses on initialization, mutation semantics, subscriptions, and the callable-hook API—not selector equality optimization.

Signature

type SetState<S> = (
  partial: Partial<S> | S | ((current: S) => Partial<S> | S),
  replace?: boolean,
) => void;

function createZustandStore<S extends object>(
  initializer: (set: SetState<S>, get: () => S) => S,
): {
  <T = S>(selector?: (state: S) => T): T;
  getState(): S;
  setState: SetState<S>;
  subscribe(listener: (next: S, previous: S) => void): () => void;
};

Examples

The initializer returns data and stable actions that close over set and get:

const useCounter = createZustandStore((set, get) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  double: () => set({ count: get().count * 2 }),
}));

useCounter.getState().increment();
useCounter.getState().double();
useCounter.getState().count; // 2

Components select values from the same provider-free store:

function Count() {
  const count = useCounter((state) => state.count);
  return React.createElement('output', null, count);
}

useCounter.setState({ count: 7 }); // mounted readers update

Notes

  • Initialize once. Require a function and call it exactly once as initializer(setState, getState). It must return a non-null state object.
  • Merge by default. Resolve a direct value or updater against the current state. With replace=false, require a non-null object and shallow-merge it into the current snapshot. With replace=true, use the resolved value exactly.
  • Skip the same snapshot. If the resolved value is Object.is the current snapshot, do nothing. Otherwise update first, then notify a snapshot copy of listeners with (nextState, previousState).
  • Subscriptions are precise. subscribe(listener) returns an unsubscribe function that removes that exact listener and remains safe when called repeatedly.
  • One callable API. The returned hook has stable getState, setState, and subscribe properties. Store state outlives every component and each factory call creates an independent store.
  • Selectors derive only. The hook validates and applies the current selector after useSyncExternalStore reads the whole snapshot. This minimal version wakes on every snapshot change, even when the selected result is equal.
  • Out of scope. Do not add selector equality, memoization, middleware, persistence, devtools, async actions, Immer, or a Provider.