Creating a store in Zustand
A Zustand store is a hook that holds both state and the actions that change it. Components select the piece of state they need.
How it works
- Create the store.
createreceives a function that getssetand returns the initial state plus actions. Herebearsis a number and the two actions change it. [1] - Bind components with selectors.
BearCounterselectsstate.bearsandControlsselects the two actions. Neither component is wrapped in a provider. [1] - Keep actions next to state.
increasePopulationpasses a function tosetto read the previous count, whileremoveAllBearspasses a plain object. [2]
Run and edit it
It runs in your browser, in a sandboxed frame that cannot see this site; the packages load from esm.sh only after you press Run.
import { create } from 'zustand'
// The store is a hook: state and actions live together
const useBearStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
const btn = { padding: '9px 16px', border: 0, borderRadius: 8, cursor: 'pointer', fontSize: 14, fontWeight: 600 }
function BearCounter() {
// Select one value; this component re-renders when it changes
const bears = useBearStore((state) => state.bears)
return <h1 style={{ margin: '0 0 18px', fontSize: 34 }}>{bears} bears around here</h1>
}
function Controls() {
const increasePopulation = useBearStore((state) => state.increasePopulation)
const removeAllBears = useBearStore((state) => state.removeAllBears)
return (
<div style={{ display: 'flex', gap: 10, justifyContent: 'center' }}>
<button style={{ ...btn, background: '#f5b84a', color: '#1a1a1a' }} onClick={increasePopulation}>one up</button>
<button style={{ ...btn, background: '#2f343f', color: '#e8eaf0' }} onClick={removeAllBears}>remove all</button>
</div>
)
}
export default function App() {
return (
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#111', fontFamily: 'system-ui, sans-serif' }}>
<div style={{ background: '#1c1f26', color: '#e8eaf0', padding: 26, borderRadius: 14, width: 400, boxSizing: 'border-box', textAlign: 'center' }}>
<BearCounter />
<Controls />
<p style={{ color: '#9aa0ad', fontSize: 13, margin: '18px 0 0' }}>Two components share one store without a provider.</p>
</div>
</div>
)
}
Click "one up" a few times, then add a third action such as removing one bear. Code written by AgentGid [1].
Click "one up" a few times, then add a third action such as removing one bear. Code written by AgentGid [1].Checked Oct 12, 2026: it starts without errors in Chromium with zustand 5.0.15, react 19.3.0, react-dom 19.3.0. Needs WebGL.
More Zustand examples
Updating state from inputs in Zustand Async actions in Zustand Using a Zustand store outside components Updating nested state in Zustand
Sources
Explanations written by AgentGid from the official docs; the numbers in brackets point here. The code marked "written by AgentGid" is ours and free to copy.