A user logs out, another logs in on the same device - and suddenly sees the previous user's cart or permissions. Whether you have 3 stores or 20, resetting state on logout is a critical task that often falls through the cracks.
Why the "Typical" Reset Fails
The most common approach is usually: reset: () => set(initialState). However, this fails in four specific ways:
- Frozen dynamic values: If you have
sessionId: crypto.randomUUID(), it was generated once at module load. Every "reset" restores that same ID. A real reset needs to re-run the initializer. - Merge instead of replace: Zustand's
setmerges by default. Leftover keys from previous states survive. You needset(fresh, true)to perform a full replacement. - Forgotten stores: A manual
logout()function calling 20 different reset actions will eventually break the day someone adds store #21. You need a centralized registry. - Persist race conditions: Resetting memory while
localStorageis still being read (rehydration) can cause the old data to overwrite your fresh state. If storage fails, Zustand might swallow the error, hanging your logout logic forever.
The Solution: zustand-reset-manager
I hit all of these walls in my own projects, so I built a small utility to handle it: zustand-reset-manager. It’s MIT-licensed, has zero runtime dependencies, and supports Zustand v4/v5.
1. Define a Resettable Store
The initializer keeps its exact Zustand signature, including middleware.
typescript
import { createResettableStore } from 'zustand-reset-manager';
export const useCart = createResettableStore<CartState>("cart")((set) => ({
items: [],
sessionId: crypto.randomUUID(), // This will be re-generated on every reset!
add: (item) => set((s) => ({ items: [...s.items, item] })),
}));
SOCIAL SHARE CARD GENERATOR