Prop-based initialization
A component or subtree needs initial state derived from props.
Zustand · Const
Use a vanilla Zustand store with React context when a store must be initialized from component props or injected into a subtree. Create it once in a provider, pass it through context, and consume selected slices with useStore.
Create a vanilla Zustand store when a component-scoped instance is needed, place that store in React context, and consume selected state with useStore. A custom hook can centralize context validation and selection for consumers.
const StoreContext = createContext<StoreApi<State> | null>(null)
const [store] = useState(() => createStore(createState))
const value = useStore(store, selector)| Name | Type | Description |
|---|---|---|
store | StoreApi<T> | A vanilla Zustand store created with createStore and supplied through React context. |
selector | (state: T) => U | A function selecting the value returned to the component from the store state. |
The selected value returned by useStore; the provider renders its children with the store available through context.
import { createContext, useContext, useState } from 'react'
import { createStore, useStore } from 'zustand'
type CounterState = { count: number; increment: () => void }
const createCounterStore = () => createStore<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
type CounterStore = ReturnType<typeof createCounterStore>
const CounterContext = createContext<CounterStore | null>(null)
function CounterProvider({ children }: { children: React.ReactNode }) {
const [store] = useState(createCounterStore)
return <CounterContext.Provider value={store}>{children}</CounterContext.Provider>
}
function Counter() {
const store = useContext(CounterContext)
if (!store) throw new Error('Missing CounterProvider')
const count = useStore(store, (state) => state.count)
const increment = useStore(store, (state) => state.increment)
return <button onClick={increment}>{count}</button>
}Creates one vanilla store for the provider, passes it through React context, and uses Zustand's useStore hook to select state and actions.
A component or subtree needs initial state derived from props.
Tests or embedded widgets need independently controllable store instances.
Repeated UI units must not share one module-level store.
Use createStore to build a vanilla store, create a React context whose value can hold that store, and provide one store instance from a component. Consumers call useStore with the context value and a selector.
Follow-up: Why not simply use create? A bound hook is convenient for a shared store, but a vanilla store plus context supports component-scoped instances and dependency injection.
Initialize the store in a lazy useState initializer, then pass the stable instance to the provider. This prevents recreating the store during ordinary provider renders.
Follow-up: How can initialization receive props? Define the store factory to accept those props and call it inside the provider's lazy initializer.
useStore takes the vanilla store and a selector, returning the selected value and subscribing the component to it. A custom hook can read the context, validate it, and delegate to useStore.
Follow-up: How can a consumer use a different equality strategy? Use useStoreWithEqualityFn with the store, selector, and equality function.
createStoreuseStorecreateContextuseContextuseStateuseStoreWithEqualityFn