[{"data":1,"prerenderedAt":122},["ShallowReactive",2],{"qa-\u002Freact\u002Fstate-management\u002Fzustand":3},{"page":4,"siblings":105,"blog":119},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"questionsCount":96,"related":97,"seo":98,"seoDescription":99,"stem":100,"subtopic":6,"topic":101,"topicSlug":102,"updated":103,"__hash__":104},"qa\u002Freact\u002Fstate-management\u002Fzustand.md","Zustand",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","React","react",{},true,"\u002Freact\u002Fstate-management\u002Fzustand",[22,27,31,35,39,43,47,51,55,59,63,67,72,76,80,84,88,92],{"id":23,"difficulty":24,"q":25,"a":26},"what-is-zustand","easy","What is Zustand and what problem does it solve?","**Zustand** (German for \"state\") is a lightweight React state-management\nlibrary built on a **flux-inspired one-way data flow** but with almost\nzero boilerplate. It stores state outside the React tree in a plain\nJavaScript object and lets any component subscribe to it without\nrequiring a Provider wrapper.\n\nThe problem it solves: Context re-renders every consumer when any part\nof the context value changes, and Redux forces you to write reducers,\naction types, action creators, and selectors just to add a counter.\nZustand replaces all of that with a single `create()` call.\n\n```js\nimport { create } from 'zustand'\n\nconst useCounterStore = create((set) => ({\n  count: 0,                          \u002F\u002F state\n  increment: () => set((s) => ({ count: s.count + 1 })), \u002F\u002F action\n  reset:     () => set({ count: 0 }),\n}))\n\n\u002F\u002F Consume in any component — no Provider needed\nfunction Counter() {\n  const count     = useCounterStore((s) => s.count)\n  const increment = useCounterStore((s) => s.increment)\n  return \u003Cbutton onClick={increment}>{count}\u003C\u002Fbutton>\n}\n```\n\nThe store is a React hook, state is mutable through `set`, and\ncomponents only re-render when the slice they selected changes.\n\n**Rule of thumb:** Reach for Zustand when Context performance starts\nhurting or when you need global state that isn't tied to a single\ncomponent subtree.\n",{"id":28,"difficulty":24,"q":29,"a":30},"create-store","How do you create a Zustand store with `create()`?","`create()` accepts a **callback** that receives `set` (and optionally\n`get`) and returns the initial state object. State properties and\n**actions** (functions that update state) live in the same object — there\nare no separate reducers or action types.\n\n```js\nimport { create } from 'zustand'\n\nconst useBearStore = create((set, get) => ({\n  bears: 0,\n  honey: 100,\n\n  \u002F\u002F Action using updater function — safe when next value depends on current\n  addBear: () => set((state) => ({ bears: state.bears + 1 })),\n\n  \u002F\u002F Action using partial object — fine when value is independent\n  removeAllBears: () => set({ bears: 0 }),\n\n  \u002F\u002F Action reading current state via get()\n  eatHoney: (amount) => {\n    const { honey } = get()          \u002F\u002F read without subscribing\n    if (honey >= amount) set({ honey: honey - amount })\n  },\n}))\n```\n\n`set` does a **shallow merge** (like `setState` in class components),\nso you only specify the keys you want to update. Pass `true` as the\nsecond argument (`set(fn, true)`) to replace rather than merge.\n\n**Rule of thumb:** Put both state fields and their mutation functions\nin one `create()` call — it keeps related data and logic together and\navoids cross-file action imports.\n",{"id":32,"difficulty":24,"q":33,"a":34},"selectors","Why should you use a selector when reading from a Zustand store?","Without a selector the component re-renders on **every store update**,\neven changes unrelated to what it displays. A **selector** is a function\npassed to the store hook that picks only the slice the component needs;\nZustand compares the return value between renders and skips the re-render\nif it hasn't changed.\n\n```js\nconst useBearStore = create(() => ({ bears: 0, honey: 100 }))\n\n\u002F\u002F ❌ No selector — subscribes to the whole store object.\n\u002F\u002F    Re-renders whenever bears OR honey changes.\nfunction BearsDisplay() {\n  const state = useBearStore()   \u002F\u002F returns { bears, honey }\n  return \u003Cspan>{state.bears}\u003C\u002Fspan>\n}\n\n\u002F\u002F ✅ Selector — subscribes only to bears.\n\u002F\u002F    Re-renders only when bears changes.\nfunction BearsDisplay() {\n  const bears = useBearStore((s) => s.bears)\n  return \u003Cspan>{bears}\u003C\u002Fspan>\n}\n```\n\nZustand uses `Object.is` equality by default. For selectors that return\nobjects or arrays, swap in `shallow` from `zustand\u002Fshallow` so that\na new object with the same keys doesn't trigger a re-render.\n\n**Rule of thumb:** Always select the smallest slice you need, just as\nyou would with a Redux `useSelector`.\n",{"id":36,"difficulty":24,"q":37,"a":38},"actions-inside-store","Should Zustand actions live inside or outside the store?","The **idiomatic Zustand approach** is to define actions **inside** the\n`create()` callback alongside the state they mutate. This co-location\nmeans actions can call `set` and `get` directly without being passed as\narguments, and consumers import a single hook instead of separate\naction creators.\n\n```js\nconst useUserStore = create((set, get) => ({\n  user: null,\n  isLoading: false,\n\n  \u002F\u002F Action defined inside — has closure access to set and get\n  setUser: (user) => set({ user }),\n\n  clearUser: () => set({ user: null }),\n\n  \u002F\u002F Read other state fields via get() inside an action\n  isAdmin: () => get().user?.role === 'admin',\n}))\n\n\u002F\u002F Consumers just call the action directly\nfunction LoginButton() {\n  const setUser = useUserStore((s) => s.setUser)\n  return \u003Cbutton onClick={() => setUser({ id: 1, role: 'admin' })}>\n    Login\n  \u003C\u002Fbutton>\n}\n```\n\nThe alternative — defining actions outside via `useUserStore.setState` —\nworks but scatters logic and is usually only worthwhile in very large\nstores where the slices pattern is used.\n\n**Rule of thumb:** Keep actions inside `create()` unless your store\ngrows so large that the slices pattern becomes necessary.\n",{"id":40,"difficulty":14,"q":41,"a":42},"async-actions","How do you handle async actions in Zustand?","Zustand requires **no special middleware** for async work. Because actions\nare plain functions, you can use `async\u002Fawait` directly. Call `set`\nonce or multiple times inside the async function to reflect loading,\nsuccess, and error states.\n\n```js\nconst usePostsStore = create((set) => ({\n  posts: [],\n  loading: false,\n  error: null,\n\n  fetchPosts: async () => {\n    set({ loading: true, error: null })        \u002F\u002F show spinner\n\n    try {\n      const res  = await fetch('\u002Fapi\u002Fposts')\n      const data = await res.json()\n      set({ posts: data, loading: false })     \u002F\u002F success\n    } catch (err) {\n      set({ error: err.message, loading: false }) \u002F\u002F failure\n    }\n  },\n}))\n\nfunction PostList() {\n  const { posts, loading, fetchPosts } = usePostsStore()\n  \u002F\u002F fetchPosts is a stable reference — safe in useEffect deps\n  useEffect(() => { fetchPosts() }, [fetchPosts])\n  if (loading) return \u003Cp>Loading…\u003C\u002Fp>\n  return \u003Cul>{posts.map(p => \u003Cli key={p.id}>{p.title}\u003C\u002Fli>)}\u003C\u002Ful>\n}\n```\n\nThis is one of Zustand's biggest DX wins over Redux, where you need\n`redux-thunk` or `redux-saga` to do the same thing.\n\n**Rule of thumb:** Write async actions exactly like any `async` function\n— no middleware, no special patterns, just `await` and `set`.\n",{"id":44,"difficulty":14,"q":45,"a":46},"shallow-equality","When and why do you use `shallow` equality in Zustand?","Zustand's default comparison is `Object.is` — fine for primitives and\nstable references, but it fails when a selector returns a **new object\nor array on every call**. Import `shallow` from `zustand\u002Fshallow` and\npass it as the second argument to suppress spurious re-renders.\n\n```js\nimport { shallow } from 'zustand\u002Fshallow'\n\nconst useStore = create(() => ({\n  name: 'Alice',\n  age: 30,\n  theme: 'dark',\n}))\n\n\u002F\u002F ❌ Without shallow — new object every render → always re-renders\nfunction Profile() {\n  const { name, age } = useStore((s) => ({ name: s.name, age: s.age }))\n  return \u003Cp>{name}, {age}\u003C\u002Fp>\n}\n\n\u002F\u002F ✅ With shallow — compares keys one level deep → re-renders only\n\u002F\u002F    when name or age actually changes\nfunction Profile() {\n  const { name, age } = useStore(\n    (s) => ({ name: s.name, age: s.age }),\n    shallow,               \u002F\u002F second argument\n  )\n  return \u003Cp>{name}, {age}\u003C\u002Fp>\n}\n\n\u002F\u002F Also works for picking multiple fields as an array\nconst [name, age] = useStore((s) => [s.name, s.age], shallow)\n```\n\n**Rule of thumb:** Use `shallow` whenever your selector returns an\nobject literal or array; skip it when the selector returns a single\nprimitive or stable reference.\n",{"id":48,"difficulty":14,"q":49,"a":50},"devtools-middleware","How do you wire up Redux DevTools with Zustand?","Wrap the `create()` callback with the **`devtools`** middleware from\n`zustand\u002Fmiddleware`. Once connected, every `set` call appears as a\nnamed action in the Redux DevTools extension, and you get time-travel\ndebugging for free.\n\n```js\nimport { create }   from 'zustand'\nimport { devtools } from 'zustand\u002Fmiddleware'\n\nconst useCounterStore = create(\n  devtools(\n    (set) => ({\n      count: 0,\n      \u002F\u002F Name each action for the DevTools action log\n      increment: () => set(\n        (s) => ({ count: s.count + 1 }),\n        false,                    \u002F\u002F don't replace — merge\n        'counter\u002Fincrement',      \u002F\u002F action name shown in DevTools\n      ),\n      reset: () => set({ count: 0 }, false, 'counter\u002Freset'),\n    }),\n    { name: 'CounterStore' },     \u002F\u002F store name shown in DevTools\n  ),\n)\n```\n\nYou can pass `{ enabled: process.env.NODE_ENV === 'development' }` to\nthe `devtools` options to strip it from production bundles.\n\n**Rule of thumb:** Add `devtools` early in development — the action\nnaming discipline pays dividends when debugging complex state flows.\n",{"id":52,"difficulty":14,"q":53,"a":54},"persist-middleware","How does the `persist` middleware work in Zustand?","The **`persist`** middleware from `zustand\u002Fmiddleware` serializes store\nstate to a storage engine (localStorage by default) after every `set`\nand rehydrates it on page load. You wrap your store definition exactly\nlike `devtools`.\n\n```js\nimport { create }  from 'zustand'\nimport { persist, createJSONStorage } from 'zustand\u002Fmiddleware'\n\nconst useSettingsStore = create(\n  persist(\n    (set) => ({\n      theme: 'dark',\n      fontSize: 16,\n      setTheme:    (t) => set({ theme: t }),\n      setFontSize: (s) => set({ fontSize: s }),\n    }),\n    {\n      name:    'user-settings',          \u002F\u002F localStorage key\n      storage: createJSONStorage(() => localStorage), \u002F\u002F default\n      \u002F\u002F Persist only a subset of state\n      partialize: (state) => ({ theme: state.theme }),\n    },\n  ),\n)\n```\n\nFor SSR \u002F Next.js, swap to `sessionStorage` or a custom storage\nadapter so hydration mismatches are avoided. `partialize` lets you\nexclude sensitive or derived fields (like loading flags) from the\npersisted snapshot.\n\n**Rule of thumb:** Always use `partialize` to be explicit about which\nfields survive a page reload — persisting loading or error flags causes\nstale UI on startup.\n",{"id":56,"difficulty":14,"q":57,"a":58},"immer-middleware","How does Zustand's `immer` middleware change how you write state updates?","By default, `set` in Zustand requires you to return a **new partial\nobject**. Wrapping with the **`immer`** middleware lets you write\nmutations directly on a draft — Immer produces the new immutable state\nbehind the scenes.\n\n```js\nimport { create }  from 'zustand'\nimport { immer  }  from 'zustand\u002Fmiddleware\u002Fimmer'\n\nconst useCartStore = create(\n  immer((set) => ({\n    items: [],\n\n    \u002F\u002F Without immer you'd write: set(s => ({ items: [...s.items, item] }))\n    addItem: (item) => set((state) => {\n      state.items.push(item)           \u002F\u002F direct mutation — Immer handles it\n    }),\n\n    removeItem: (id) => set((state) => {\n      state.items = state.items.filter(i => i.id !== id)\n    }),\n\n    updateQty: (id, qty) => set((state) => {\n      const item = state.items.find(i => i.id === id)\n      if (item) item.qty = qty         \u002F\u002F nested mutation — safe with Immer\n    }),\n  })),\n)\n```\n\nWithout `immer`, updating nested objects requires spreading every layer\nmanually. With it you write imperative mutations and Immer converts them\nto structural shares.\n\n**Rule of thumb:** Add `immer` when your state has deeply nested\nstructures; skip it for flat state where spread syntax is readable\nenough.\n",{"id":60,"difficulty":14,"q":61,"a":62},"slices-pattern","What is the slices pattern in Zustand and when should you use it?","As a store grows, cramming all state and actions into one `create()` call\nbecomes unwieldy. The **slices pattern** splits the store into separate\nfunctions (slices), each responsible for a domain, and merges them in a\nsingle `create()` call.\n\n```js\n\u002F\u002F slices\u002FauthSlice.js\nexport const createAuthSlice = (set) => ({\n  user: null,\n  login:  (u) => set({ user: u }),\n  logout: ()  => set({ user: null }),\n})\n\n\u002F\u002F slices\u002FcartSlice.js\nexport const createCartSlice = (set) => ({\n  items: [],\n  addItem:    (item) => set((s) => ({ items: [...s.items, item] })),\n  clearCart:  ()     => set({ items: [] }),\n})\n\n\u002F\u002F store.js — combine slices into one store\nimport { create }          from 'zustand'\nimport { createAuthSlice } from '.\u002Fslices\u002FauthSlice'\nimport { createCartSlice } from '.\u002Fslices\u002FcartSlice'\n\nexport const useStore = create((...args) => ({\n  ...createAuthSlice(...args),\n  ...createCartSlice(...args),\n}))\n\n\u002F\u002F Consumers select from the unified store as usual\nconst user  = useStore((s) => s.user)\nconst items = useStore((s) => s.items)\n```\n\nThis is the Zustand-recommended approach for large stores. Each slice\nfile stays focused and testable independently.\n\n**Rule of thumb:** Introduce slices once your store exceeds ~5 concerns\nor the single file becomes hard to navigate.\n",{"id":64,"difficulty":14,"q":65,"a":66},"subscribe-outside-react","How do you subscribe to a Zustand store outside of a React component?","The store object created by `create()` is also a vanilla store with a\n`.subscribe()` method. You can call it in plain JS modules, Node.js\nscripts, or outside the component tree — no hooks needed.\n\n```js\nconst useStore = create((set) => ({\n  count: 0,\n  increment: () => set((s) => ({ count: s.count + 1 })),\n}))\n\n\u002F\u002F Subscribe outside React\nconst unsub = useStore.subscribe(\n  (state) => state.count,   \u002F\u002F selector — called only when count changes\n  (count, prevCount) => {\n    console.log(`count changed: ${prevCount} → ${count}`)\n    if (count >= 10) analytics.track('milestone_10')\n  },\n)\n\n\u002F\u002F Read state without subscribing\nconst current = useStore.getState().count\n\n\u002F\u002F Set state without a component\nuseStore.setState({ count: 0 })\n\n\u002F\u002F Clean up when done\nunsub()\n```\n\nThis is useful for analytics side effects, syncing with non-React\nsystems, or writing integration tests that assert state without\nrendering.\n\n**Rule of thumb:** Use `.subscribe()` \u002F `.getState()` \u002F `.setState()`\nfor interactions with the store that live outside the React lifecycle.\n",{"id":68,"difficulty":69,"q":70,"a":71},"zustand-vs-redux-toolkit","hard","What are the trade-offs between Zustand and Redux Toolkit?","Both libraries manage global state in a React app, but they occupy\ndifferent points on the complexity\u002Fpower spectrum.\n\n| Concern | Zustand | Redux Toolkit |\n|---|---|---|\n| Bundle size | ~1 kB | ~12 kB |\n| Boilerplate | Minimal (`create` + actions) | Slices + configure + reducers |\n| Devtools | Yes (via middleware) | First-class, built-in |\n| Async | Plain async functions | `createAsyncThunk` \u002F RTK Query |\n| Data fetching | DIY or Zustand + SWR\u002FTanStack | RTK Query (cache, dedup) |\n| Middleware ecosystem | Small (devtools, persist, immer) | Large (mature) |\n| TypeScript | Good | Excellent |\n| Learning curve | Low | Medium-High |\n\n```js\n\u002F\u002F Same counter — Zustand vs RTK\n\n\u002F\u002F Zustand (6 lines)\nconst useCounter = create((set) => ({\n  value: 0,\n  increment: () => set((s) => ({ value: s.value + 1 })),\n}))\n\n\u002F\u002F Redux Toolkit (25+ lines)\nconst counterSlice = createSlice({\n  name: 'counter',\n  initialState: { value: 0 },\n  reducers: { increment: (state) => { state.value++ } },\n})\nconst store = configureStore({ reducer: { counter: counterSlice.reducer } })\n```\n\nChoose Redux Toolkit when: you have a large team that benefits from\nstrict conventions, you need RTK Query for server-cache management, or\nyou're already invested in the Redux ecosystem. Choose Zustand when: you\nwant quick setup, smaller bundle, or a library that stays out of your way.\n\n**Rule of thumb:** Zustand for small-to-medium apps; Redux Toolkit when\nthe app is large, team is big, or RTK Query's server-state caching is\nworth the extra weight.\n",{"id":73,"difficulty":69,"q":74,"a":75},"zustand-vs-context","How does Zustand compare to the React Context API for global state?","Context and Zustand solve the same problem — sharing state across the\ntree — but with very different performance models.\n\n```jsx\n\u002F\u002F Context: every consumer re-renders when ANY part of value changes\nconst AppCtx = createContext(null)\nfunction AppProvider({ children }) {\n  const [count, setCount] = useState(0)\n  const [user,  setUser ] = useState(null)\n  \u002F\u002F ❌ Changing count re-renders components that only read user\n  return \u003CAppCtx.Provider value={{ count, setCount, user, setUser }}>\n    {children}\n  \u003C\u002FAppCtx.Provider>\n}\n\n\u002F\u002F Zustand: each component subscribes only to the slice it selects\nconst useAppStore = create((set) => ({\n  count: 0, setCount: (n) => set({ count: n }),\n  user:  null, setUser: (u) => set({ user: u }),\n}))\n\n\u002F\u002F This component NEVER re-renders when count changes\nfunction UserMenu() {\n  const user = useAppStore((s) => s.user)\n  return \u003Cspan>{user?.name}\u003C\u002Fspan>\n}\n```\n\nAdditional differences:\n\n- **Provider**: Context requires a Provider in the tree; Zustand needs\n  none.\n- **Outside React**: Zustand is accessible without hooks; Context is not.\n- **DevTools**: Zustand supports the Redux DevTools extension; Context\n  has no built-in equivalent.\n- **Bundle overhead**: Context adds zero bytes; Zustand adds ~1 kB.\n\n**Rule of thumb:** Use Context for infrequently-changing cross-cutting\nconcerns (theme, locale, auth token); switch to Zustand when multiple\ncomponents subscribe to frequently-changing shared state.\n",{"id":77,"difficulty":14,"q":78,"a":79},"testing-zustand","How do you test a Zustand store?","Zustand stores are plain JS objects — you can call actions directly and\nassert state without rendering any components.\n\n```js\n\u002F\u002F store.test.js\nimport { describe, it, expect, beforeEach } from 'vitest'\nimport { useCartStore } from '.\u002FcartStore'\n\n\u002F\u002F Reset store state between tests to prevent leakage\nbeforeEach(() => {\n  useCartStore.setState({ items: [] })  \u002F\u002F reset to initial\n})\n\ndescribe('cart store', () => {\n  it('adds an item', () => {\n    useCartStore.getState().addItem({ id: 1, name: 'Book', qty: 1 })\n    expect(useCartStore.getState().items).toHaveLength(1)\n  })\n\n  it('removes an item', () => {\n    useCartStore.setState({ items: [{ id: 1, name: 'Book', qty: 1 }] })\n    useCartStore.getState().removeItem(1)\n    expect(useCartStore.getState().items).toHaveLength(0)\n  })\n})\n```\n\nFor component tests, render normally with `@testing-library\u002Freact` —\nno mocking needed. If you want to test a component in isolation, seed\nthe store with `setState` before rendering and reset with `setState`\nin `beforeEach`.\n\n**Rule of thumb:** Test stores directly via `.getState()` \u002F `.setState()`\nfor unit tests; use the real store (no mocks) for component integration\ntests.\n",{"id":81,"difficulty":14,"q":82,"a":83},"typescript-zustand","How do you add TypeScript types to a Zustand store?","Define an **interface** (or type) for the store shape and pass it as the\ngeneric type argument to `create`. Zustand infers the rest automatically.\n\n```ts\nimport { create } from 'zustand'\n\n\u002F\u002F 1. Define the shape of state + actions\ninterface BearState {\n  bears:     number\n  honey:     number\n  addBear:   () => void\n  eatHoney:  (amount: number) => void\n}\n\n\u002F\u002F 2. Pass the type to create — the callback parameter is typed\nconst useBearStore = create\u003CBearState>()((set, get) => ({\n  bears: 0,\n  honey: 100,\n\n  addBear: () => set((s) => ({ bears: s.bears + 1 })),\n\n  eatHoney: (amount) => {\n    const { honey } = get()\n    if (honey >= amount) set({ honey: honey - amount })\n  },\n}))\n\n\u002F\u002F Selectors are fully typed — TypeScript knows bears is number\nconst bears: number = useBearStore((s) => s.bears)\n```\n\nNote the extra `()` after `create\u003CBearState>()` — this is a TypeScript\ncurrying workaround required to preserve type inference on the callback\nwithout explicitly annotating `set`.\n\n**Rule of thumb:** Always define the store interface first; it acts as\nliving documentation of every field and action the store owns.\n",{"id":85,"difficulty":24,"q":86,"a":87},"when-to-use-zustand","When should you prefer Zustand over component-local state?","**Component-local state** (`useState` \u002F `useReducer`) is the right\ndefault. Lift to Zustand only when one of these conditions holds:\n\n- **Multiple unrelated components** need to read or mutate the same\n  state (avoids prop drilling or a Context that's too coarse).\n- The state **outlives** the component (e.g., persisted cart that should\n  survive route changes).\n- You need to **read or update state outside React** (analytics,\n  WebSocket handlers, service workers).\n- **Performance**: the state changes frequently and many components\n  depend on it — Context would cause a render cascade.\n\n```jsx\n\u002F\u002F ✅ Local state — belongs to one component\nfunction SearchInput() {\n  const [query, setQuery] = useState('')\n  return \u003Cinput value={query} onChange={e => setQuery(e.target.value)} \u002F>\n}\n\n\u002F\u002F ✅ Zustand — notifications consumed by Navbar, Toast, and a WebSocket\nconst useNotifStore = create((set) => ({\n  notifs: [],\n  add:    (n) => set((s) => ({ notifs: [n, ...s.notifs] })),\n  clear:  ()  => set({ notifs: [] }),\n}))\n```\n\n**Rule of thumb:** Default to `useState`; reach for Zustand when state\nneeds to be shared across component boundaries or accessed outside React.\n",{"id":89,"difficulty":14,"q":90,"a":91},"reset-store-state","What is the recommended way to reset a Zustand store to its initial state?","Keep a reference to the **initial state** and call `set` with it in a\n`reset` action. Because `set` does a shallow merge by default, passing\n`true` as the second argument does a full replace, which avoids stale\nkeys if the store shape has changed.\n\n```js\nimport { create } from 'zustand'\n\n\u002F\u002F Capture initial state outside create() so it's always available\nconst initialState = {\n  user:    null,\n  cart:    [],\n  filters: { sort: 'newest', page: 1 },\n}\n\nconst useStore = create((set) => ({\n  ...initialState,\n\n  setUser:  (u) => set({ user: u }),\n  addToCart: (item) => set((s) => ({ cart: [...s.cart, item] })),\n\n  \u002F\u002F Pass true to replace — ensures every key goes back to initial\n  resetAll: () => set(initialState, true),\n\n  \u002F\u002F Or reset only a slice\n  clearCart: () => set({ cart: [] }),\n}))\n\n\u002F\u002F Called at logout\nfunction handleLogout() {\n  useStore.getState().resetAll()\n  router.push('\u002Flogin')\n}\n```\n\nThis pattern is also the standard way to reset stores in tests:\n`useStore.setState(initialState, true)` in a `beforeEach`.\n\n**Rule of thumb:** Always store `initialState` in a const above\n`create()` so resets stay in sync with the store's definition.\n",{"id":93,"difficulty":14,"q":94,"a":95},"derived-computed-values","How do you derive computed values from a Zustand store?","Zustand has no built-in \"computed\" concept. The two idiomatic approaches\nare **inline selector logic** in `useStore()` (for simple derivations)\nand **memoized selectors** via a library like `reselect` or a plain\n`useMemo` (for expensive ones).\n\n```js\nconst useCartStore = create(() => ({\n  items: [\n    { id: 1, name: 'Book',  price: 12, qty: 2 },\n    { id: 2, name: 'Shirt', price: 30, qty: 1 },\n  ],\n}))\n\n\u002F\u002F ─── Option 1: derive inline in the selector (simple, zero extra deps) ───\nfunction CartTotal() {\n  const total = useCartStore((s) =>\n    s.items.reduce((sum, item) => sum + item.price * item.qty, 0)\n  )\n  return \u003Cstrong>Total: ${total}\u003C\u002Fstrong>\n}\n\u002F\u002F Re-renders only when items changes; computation runs on every render\n\n\u002F\u002F ─── Option 2: store a selector factory (avoid recompute if items unchanged)\nimport { useMemo } from 'react'\nfunction CartSummary() {\n  const items = useCartStore((s) => s.items)\n  const total = useMemo(\n    () => items.reduce((sum, i) => sum + i.price * i.qty, 0),\n    [items],  \u002F\u002F only recalculates when items reference changes\n  )\n  return \u003Cp>{items.length} items — ${total}\u003C\u002Fp>\n}\n```\n\nStoring derived values inside the store itself is an anti-pattern —\nthey can get out of sync if the source data is updated directly.\n\n**Rule of thumb:** Keep derived values out of the store; compute them\nin selectors or `useMemo` so they're always consistent with their\nsource.\n",18,null,{"description":11},"Zustand interview questions — create store, selectors, async actions, devtools, persist middleware, slices pattern, and Zustand vs Redux comparison.","react\u002Fstate-management\u002Fzustand","State Management","state-management","2026-06-24","s8StsaWWxbjyaa7HDzK8qvBUTJnuw_BkENdyoqNrypU",[106,110,111,115],{"subtopic":107,"path":108,"order":109},"Redux Toolkit","\u002Freact\u002Fstate-management\u002Fredux-toolkit",1,{"subtopic":6,"path":20,"order":12},{"subtopic":112,"path":113,"order":114},"Context vs Redux","\u002Freact\u002Fstate-management\u002Fcontext-vs-redux",3,{"subtopic":116,"path":117,"order":118},"Async State & React Query","\u002Freact\u002Fstate-management\u002Fasync-state-react-query",4,{"path":120,"title":121},"\u002Fblog\u002Freact-zustand-guide","Zustand for React — Complete Interview Guide",1782244101072]