# How Zustand works

Zustand puts state and its update functions in a store, then exposes that store through a React hook.

## Your store is a hook

Create a store with [`create`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand#create) and use its returned hook inside components. Select the state each component needs. Zustand recommends colocating update functions, or actions, with the state they update, but does not require dispatched actions or reducers.

The returned hook also carries store API utilities for non-component access. For component reads, use the hook's selector to focus on the value the component needs.

## How updates flow

The component reads a selected value from the store hook. An action calls `set` with an immutable update; Zustand merges the changed fields and notifies subscribers, and React reads the selection again.

```mermaid
flowchart LR
  A["Component selects state"] --> B["Store hook"]
  B --> C["Selected value renders"]
  D["Component calls action"] --> E["set() with immutable update"]
  E --> F["Store merges and notifies"]
  F --> B
```

## Keep updates immutable

Use `set` or `setState` to update state. For a flat update, return only the changed fields: Zustand merges that partial state with the current state. The merge is shallow and covers one level, so copy a nested object yourself when changing one of its fields. Actions can live in the store; reducers and dispatch are optional patterns.

## Select what a component needs

Select the smallest value the component needs. Atomic selections use strict equality by default. If a selector constructs an object or array from several state values, [`useShallow`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand-react-shallow#useshallow) keeps a shallowly equal result stable so unchanged selections do not cause an unnecessary re-render.

## See the pieces together

This mounted React example renders a counter, a second readout through [`useStore`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand#usestore), and an **Add one** button. The `inc` action updates the count through `set`; clicking the button updates the count in both components.

Install the packages used by the React examples. React is also required by the `zustand/react/shallow` entry point:

```bash
npm install zustand react react-dom
```

```tsx
import { createRoot } from 'react-dom/client'
import { create, useStore } from 'zustand'
import { useShallow } from 'zustand/react/shallow'

type CounterState = {
  count: number
  inc: () => void
}

const useCounterStore = create<CounterState>()((set) => ({
  count: 0,
  inc: () => set((state) => ({ count: state.count + 1 })),
}))

function Counter() {
  const { count, inc } = useCounterStore(
    useShallow((state) => ({ count: state.count, inc: state.inc })),
  )

  return (
    <main>
      <p>Count: {count}</p>
      <button onClick={inc}>Add one</button>
    </main>
  )
}

function CountReadout() {
  const count = useStore(useCounterStore, (state) => state.count)
  return <p>Count via useStore: {count}</p>
}

function App() {
  return (
    <>
      <Counter />
      <CountReadout />
    </>
  )
}

const container = document.getElementById('root')!
createRoot(container).render(<App />)
```

Provide a root element in the browser page where this entry runs:

```html
<div id="root"></div>
```

The state update returns only `count`; Zustand's shallow merge retains the `inc` action. The selector creates an object, and `useShallow` reuses its previous result when the selected fields remain shallowly equal.

## Pitfalls and next steps

- For selectors that create new references, see [Select state efficiently](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/select-state-efficiently).
- For nested updates, see [Update nested state](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/update-nested-state).
- For the React setup and immutable update basics, see [React quick start](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/react-quick-start).
- For server-rendered Next.js applications, see [Set up Zustand in Next.js](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/set-up-zustand-in-nextjs).
- Try the [live Zustand demo](https://zustand-demo.pmnd.rs/) to see a store-driven interface running.
