OMAR
Field NotesCV
Zustand: State Management You Can Read in One Sitting
← All Notes
Frontend01 August 2026 · 3 min read

Zustand: State Management You Can Read in One Sitting

A store is a hook. That is the whole idea. No providers, no actions file, no reducer ceremony — and it scales further than the ceremony did.

The honest reason most React apps have complicated state management is not complexity. It is that the popular option arrived with a required folder structure, and folder structures outlive the reasons for them.

Zustand's entire API is that a store is a hook.

import { create } from 'zustand'

export const useCart = create((set) => ({
  items: [],
  add: (item) => set((s) => ({ items: [...s.items, item] })),
  remove: (id) => set((s) => ({ items: s.items.filter(i => i.id !== id) })),
  clear: () => set({ items: [] }),
}))

That is the store, the actions and the types, in one file you can read without scrolling.

Using it

function CartBadge() {
  const count = useCart((s) => s.items.length)
  return <span>{count}</span>
}

No provider wrapping the app. No context. And note the selector: CartBadge re-renders when the count changes, not when anything in the cart changes. That is the performance story handled by the same syntax you were already writing, rather than by a memoisation pass you do later under deadline.

Why it survives growth

The objection is always that it will not scale. In practice the thing that fails to scale is indirection — the hop from component to action creator to reducer to selector, across four files, to change one boolean. Zustand keeps the hop count at one, and you split by store rather than by layer: a cart store, a filters store, an editor store. Each one is small enough to read whole.

Middleware covers the rest when you need it:

import { persist } from 'zustand/middleware'

export const useSettings = create(
  persist((set) => ({ theme: 'dark', setTheme: (theme) => set({ theme }) }),
    { name: 'settings' })
)

Local storage, devtools and immer are opt-in wrappers rather than architecture decisions you make on day one.

The boundary that matters

Zustand is for state you own — UI mode, a wizard's current step, an editor's selection, a cart before it is submitted. It is not a cache. If the data came from an API, it belongs in a query layer that understands staleness, not in a store that will happily hold last week's answer forever.

Getting that boundary right is most of the benefit. Almost every "which state library" argument I have sat through was actually an argument about server data being kept in the wrong place.

Why I reach for it on client work

Handover. A store a client's next developer can read in five minutes is worth more than a pattern that is technically superior and practically abandoned. Zustand is a small dependency, a small mental model, and nothing in it needs a diagram to explain.

Resources

ReactStateOpen Source

Need this built properly?

I build secure, fast, bilingual platforms for clients across Egypt, Saudi Arabia, the UAE and Kuwait.

Keep Reading