Skip to main content
In cases where dependency injection is needed, such as when a store should be initialized with props from a component, the recommended approach is to use a vanilla store with React.context.
1

Create a store with createStore

First, create a store creator function that accepts initial props:
import { createStore } from 'zustand'

interface BearProps {
  bears: number
}

interface BearState extends BearProps {
  addBear: () => void
}

type BearStore = ReturnType<typeof createBearStore>

const createBearStore = (initProps?: Partial<BearProps>) => {
  const DEFAULT_PROPS: BearProps = {
    bears: 0,
  }
  return createStore<BearState>()((set) => ({
    ...DEFAULT_PROPS,
    ...initProps,
    addBear: () => set((state) => ({ bears: ++state.bears })),
  }))
}
2

Create a React context

Create a context to hold the store instance:
import { createContext } from 'react'

export const BearContext = createContext<BearStore | null>(null)
3

Set up the Provider

Wrap your components with the context provider:
import { useState } from 'react'

function App() {
  const [store] = useState(() => createBearStore())
  return (
    <BearContext.Provider value={store}>
      <BasicConsumer />
    </BearContext.Provider>
  )
}
4

Consume the store

Use the store in your components:
import { useContext } from 'react'
import { useStore } from 'zustand'

function BasicConsumer() {
  const store = useContext(BearContext)
  if (!store) throw new Error('Missing BearContext.Provider in the tree')

  const bears = useStore(store, (s) => s.bears)
  const addBear = useStore(store, (s) => s.addBear)

  return (
    <>
      <div>{bears} Bears.</div>
      <button onClick={addBear}>Add bear</button>
    </>
  )
}

Common Patterns

Create a reusable provider component that accepts props:
import { useState } from 'react'

type BearProviderProps = React.PropsWithChildren<BearProps>

function BearProvider({ children, ...props }: BearProviderProps) {
  const [store] = useState(() => createBearStore(props))
  return <BearContext.Provider value={store}>{children}</BearContext.Provider>
}
Create a custom hook to mimic the hook returned by create:
import { useContext } from 'react'
import { useStore } from 'zustand'

function useBearContext<T>(selector: (state: BearState) => T): T {
  const store = useContext(BearContext)
  if (!store) throw new Error('Missing BearContext.Provider in the tree')
  return useStore(store, selector)
}
Then use it in your components:
function CommonConsumer() {
  const bears = useBearContext((s) => s.bears)
  const addBear = useBearContext((s) => s.addBear)
  return (
    <>
      <div>{bears} Bears.</div>
      <button onClick={addBear}>Add bear</button>
    </>
  )
}
Use useShallow to prevent unnecessary re-renders when returning computed arrays or objects:
import { useShallow } from 'zustand/react/shallow'

const meals = ['Salmon', 'Berries', 'Nuts']

function CommonConsumer() {
  const bearMealsOrder = useBearContext(
    useShallow((s) =>
      Array.from({ length: s.bears }).map((_, index) =>
        meals.at(index % meals.length),
      ),
    ),
  )
  return (
    <>
      Order:
      <ul>
        {bearMealsOrder.map((meal) => (
          <li key={meal}>{meal}</li>
        ))}
      </ul>
    </>
  )
}
Allow custom equality functions by using useStoreWithEqualityFn:
import { useContext } from 'react'
import { useStoreWithEqualityFn } from 'zustand/traditional'

function useBearContext<T>(
  selector: (state: BearState) => T,
  equalityFn?: (left: T, right: T) => boolean,
): T {
  const store = useContext(BearContext)
  if (!store) throw new Error('Missing BearContext.Provider in the tree')
  return useStoreWithEqualityFn(store, selector, equalityFn)
}

Complete Example

Putting it all together with a provider wrapper and custom hook:
function App2() {
  return (
    <BearProvider bears={2}>
      <HookConsumer />
    </BearProvider>
  )
}
This pattern is particularly useful when you need different instances of the same store in different parts of your application tree, each initialized with different props.

Build docs developers (and LLMs) love