[](https://github.com/react-spring/zustand/actions?query=workflow%3ALint)
[](https://bundlephobia.com/result?p=zustand)
[](https://www.npmjs.com/package/zustand)
[](https://www.npmjs.com/package/zustand)
[](https://discord.gg/ZZjjNvJ)
A small, fast and scaleable bearbones state-management solution. Has a comfy api based on hooks, isn't boilerplatey or opinionated, but still just enough to be explicit and flux-like.
Don't disregard it because it's cute. It has quite the claws, lots of time was spent to deal with common pitfalls, like the dreaded [zombie child problem](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children), [react concurrency](https://github.com/bvaughn/rfcs/blob/useMutableSource/text/0000-use-mutable-source.md), and [context loss](https://github.com/facebook/react/issues/13332) between mixed renderers. It may be the one state-manager in the React space that gets all of these right.
You can try a live demo [here](https://codesandbox.io/s/dazzling-moon-itop4).
```bash
npm install zustand
```
### First create a store
Your store is a hook! You can put anything in it: primitives, objects, functions. The `set` function *merges* state.
```jsx
import create from 'zustand'
const useStore = create(set => ({
bears: 0,
increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 })
}))
```
### Then bind your components, and that's it!
Use the hook anywhere, no providers needed. Select your state and the component will re-render on changes.
```jsx
function BearCounter() {
const bears = useStore(state => state.bears)
return
{bears} around here ...
}
function Controls() {
const increasePopulation = useStore(state => state.increasePopulation)
return
}
```
#### Why zustand over react-redux?
* Simple and un-opinionated
* Makes hooks the primary means of consuming state
* Doesn't wrap your app in context providers
* [Can inform components transiently (without causing render)](#transient-updates-for-often-occuring-state-changes)
---
# Recipes
## Fetching everything
You can, but bear in mind that it will cause the component to update on every state change!
```jsx
const state = useStore()
```
## Selecting multiple state slices
It detects changes with strict-equality (old === new) by default, this is efficient for atomic state picks.
```jsx
const nuts = useStore(state => state.nuts)
const honey = useStore(state => state.honey)
```
If you want to construct a single object with multiple state-picks inside, similar to redux's mapStateToProps, you can tell zustand that you want the object to be diffed shallowly by passing an alternative equality function.
```jsx
import shallow from 'zustand/shallow'
// Object pick, re-renders the component when either state.nuts or state.honey change
const { nuts, honey } = useStore(state => ({ nuts: state.nuts, honey: state.honey }), shallow)
// Array pick, re-renders the component when either state.nuts or state.honey change
const [nuts, honey] = useStore(state => [state.nuts, state.honey], shallow)
// Mapped picks, re-renders the component when state.treats changes in order, count or keys
const treats = useStore(state => Object.keys(state.treats), shallow)
```
## Fetching from multiple stores
Since you can create as many stores as you like, forwarding results to succeeding selectors is as natural as it gets.
```jsx
const currentBear = useCredentialsStore(state => state.currentBear)
const bear = useBearStore(state => state.bears[currentBear])
```
## Memoizing selectors
It is generally recommended to memoize selectors with useCallback. This will prevent unnecessary computations each render. It also allows React to optimize performance in concurrent mode.
```jsx
const fruit = useStore(useCallback(state => state.fruits[id], [id]))
```
If a selector doesn't depend on scope, you can define it outside the render function to obtain a fixed reference without useCallback.
```jsx
const selector = state => state.berries
function Component() {
const berries = useStore(selector)
```
## Overwriting state
The `set` function has a second argument, `false` by default. Instead of merging, it will replace the state model. Be careful not to wipe out parts you rely on, like actions.
```jsx
import omit from "lodash-es/omit"
const useStore = create(set => ({
salmon: 1,
tuna: 2,
deleteEverything: () => set({ }, true), // clears the entire store, actions included
deleteTuna: () => set(state => omit(state, ['tuna']), true)
}))
```
## Async actions
Just call `set` when you're ready, zustand doesn't care if your actions are async or not.
```jsx
const useStore = create(set => ({
fishies: {},
fetch: async pond => {
const response = await fetch(pond)
set({ fishies: await response.json() })
}
}))
```
## Read from state in actions
`set` allows fn-updates `set(state => result)`, but you still have access to state outside of it through `get`.
```jsx
const useStore = create((set, get) => ({
sound: "grunt",
action: () => {
const sound = get().sound
// ...
}
})
```
## Reading/writing state and reacting to changes outside of components
Sometimes you need to access state in a non-reactive way, or act upon the store. For these cases the resulting hook has utility functions attached to its prototype.
```jsx
const useStore = create(() => ({ paw: true, snout: true, fur: true }))
// Getting non-reactive fresh state
const paw = useStore.getState().paw
// Listening to all changes, fires on every change
const unsub1 = useStore.subscribe(console.log)
// Listening to selected changes, in this case when "paw" changes
const unsub2 = useStore.subscribe(console.log, state => state.paw)
// Subscribe also supports an optional equality function
const unsub3 = useStore.subscribe(console.log, state => [state.paw, state.fur], shallow)
// Subscribe also exposes the previous value
const unsub4 = useStore.subscribe((paw, previousPaw) => console.log(paw, previousPaw), state => state.paw)
// Updating state, will trigger listeners
useStore.setState({ paw: false })
// Unsubscribe listeners
unsub1()
unsub2()
unsub3()
unsub4()
// Destroying the store (removing all listeners)
useStore.destroy()
// You can of course use the hook as you always would
function Component() {
const paw = useStore(state => state.paw)
```
## Using zustand without React
Zustands core can be imported and used without the React dependency. The only difference is that the create function does not return a hook, but the api utilities.
```jsx
import create from 'zustand/vanilla'
const store = create(() => ({ ... }))
const { getState, setState, subscribe, destroy } = store
```
You can even consume an existing vanilla store with React:
```jsx
import create from 'zustand'
import vanillaStore from './vanillaStore'
const useStore = create(vanillaStore)
```
## Transient updates (for often occuring state-changes)
The subscribe function allows components to bind to a state-portion without forcing re-render on changes. Best combine it with useEffect for automatic unsubscribe on unmount. This can make a [drastic](https://codesandbox.io/s/peaceful-johnson-txtws) performance impact when you are allowed to mutate the view directly.
```jsx
const useStore = create(set => ({ scratches: 0, ... }))
function Component() {
// Fetch initial state
const scratchRef = useRef(useStore.getState().scratches)
// Connect to the store on mount, disconnect on unmount, catch state-changes in a reference
useEffect(() => useStore.subscribe(
scratches => (scratchRef.current = scratches),
state => state.scratches
), [])
```
## Sick of reducers and changing nested state? Use Immer!
Reducing nested structures is tiresome. Have you tried [immer](https://github.com/mweststrate/immer)?
```jsx
import produce from 'immer'
const useStore = create(set => ({
lush: { forest: { contains: { a: "bear" } } },
set: fn => set(produce(fn)),
}))
const set = useStore(state => state.set)
set(state => {
state.lush.forest.contains = null
})
```
## Middleware
You can functionally compose your store any way you like.
```jsx
// Log every time state is changed
const log = config => (set, get, api) => config(args => {
console.log(" applying", args)
set(args)
console.log(" new state", get())
}, get, api)
// Turn the set method into an immer proxy
const immer = config => (set, get, api) => config(fn => set(produce(fn)), get, api)
const useStore = create(
log(
immer((set) => ({
bees: false,
setBees: (input) => set((state) => void (state.bees = input)),
})),
),
)
```
How to pipe middlewares
```js
import create from "zustand"
import produce from "immer"
import pipe from "ramda/es/pipe"
/* log and immer functions from previous example */
/* you can pipe as many middlewares as you want */
const createStore = pipe(log, immer, create)
const useStore = createStore(set => ({
bears: 1,
increasePopulation: () => set(state => ({ bears: state.bears + 1 }))
}))
export default useStore
```
For a TS example see the following [discussion](https://github.com/pmndrs/zustand/discussions/224#discussioncomment-118208)
How to type immer middleware in TypeScript
```ts
import { State, StateCreator } from 'zustand'
import produce, { Draft } from 'immer'
const immer = (
config: StateCreator) => void) => void>
): StateCreator => (set, get, api) =>
config((fn) => set(produce(fn) as (state: T) => T), get, api)
```
## Persist middleware
You can persist you store's data using any kind of storage.
```jsx
import create from "zustand"
import { persist } from "zustand/middleware"
export const useStore = create(persist(
(set, get) => ({
fishes: 0,
addAFish: () => set({ fish: get().fish + 1 })
}),
{
name: "food-storage", // unique name
getStorage: () => sessionStorage, // (optional) by default the 'localStorage' is used
}
))
```
## Can't live without redux-like reducers and action types?
```jsx
const types = { increase: "INCREASE", decrease: "DECREASE" }
const reducer = (state, { type, by = 1 }) => {
switch (type) {
case types.increase: return { grumpiness: state.grumpiness + by }
case types.decrease: return { grumpiness: state.grumpiness - by }
}
}
const useStore = create(set => ({
grumpiness: 0,
dispatch: args => set(state => reducer(state, args)),
}))
const dispatch = useStore(state => state.dispatch)
dispatch({ type: types.increase, by: 2 })
```
Or, just use our redux-middleware. It wires up your main-reducer, sets initial state, and adds a dispatch function to the state itself and the vanilla api. Try [this](https://codesandbox.io/s/amazing-kepler-swxol) example.
```jsx
import { redux } from 'zustand/middleware'
const useStore = create(redux(reducer, initialState))
```
## Redux devtools
```jsx
import { devtools } from 'zustand/middleware'
// Usage with a plain action store, it will log actions as "setState"
const useStore = create(devtools(store))
// Usage with a redux store, it will log full action types
const useStore = create(devtools(redux(reducer, initialState)))
```
devtools takes the store function as its first argument, optionally you can name the store with a second argument: `devtools(store, "MyStore")`, which will be prefixed to your actions.
## TypeScript
```tsx
type State = {
bears: number
increase: (by: number) => void
}
const useStore = create(set => ({
bears: 0,
increase: (by) => set(state => ({ bears: state.bears + by })),
}))
```
You can also use an `interface`:
```tsx
import { State } from 'zustand';
interface BearState extends State {
bears: number
increase: (by: number) => void
}
```
Or, use `combine` and let tsc infer types.
```tsx
import { combine } from 'zustand/middleware'
const useStore = create(
combine(
{ bears: 0 },
(set) => ({ increase: (by: number) => set((state) => ({ bears: state.bears + by })) })
),
)
```
## Testing
For information regarding testing with Zustand, visit the dedicated [Wiki page](https://github.com/pmndrs/zustand/wiki/Testing).