# Update state with actions

Use colocated actions when React controls need to update shared state. This example displays a count starting at `0`; the **+1** and **+5** buttons increase it from its previous value by the chosen amount.

Create the store with [`create`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand#create), then select the state and actions each component needs. The returned store is a hook, so you do not need a provider. Keep update functions alongside state rather than introducing dispatched actions or reducers for this task.

## 1. Define a typed action

In your React TypeScript project, add `counter-store.ts`. If you have not installed Zustand, run:

```bash
npm install zustand
```

Extend the [React quick start](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/react-quick-start) pattern with an action argument: `inc` accepts a numeric amount and returns `void`. Use a functional update because the next count depends on the current store state.

```ts title="counter-store.ts"
import { create } from 'zustand'

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

export const useCounterStore = create<CounterStore>()((set) => ({
  count: 0,
  inc: (by) => set((state) => ({ count: state.count + by })),
}))
```

`set` calls the updater with the current state, shallowly merges the returned object into the store, and notifies listeners. Returning only `{ count: ... }` preserves `inc`; you do not need to spread the whole store into this flat update.

## 2. Bind the action to a React control

Use this browser entry point with an HTML element whose ID is `root`, as in the [React quick start](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/react-quick-start). Keep the starter's separate selectors, and wrap each button handler to pass the amount to `inc` rather than the click event.

```tsx title="main.tsx"
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { useCounterStore } from './counter-store'

function Counter() {
  const count = useCounterStore((state) => state.count)
  const inc = useCounterStore((state) => state.inc)

  return (
    <main style={{ minHeight: 200, padding: 24 }}>
      <p>Count: {count}</p>
      <button type="button" onClick={() => inc(1)}>
        +1
      </button>
      <button type="button" onClick={() => inc(5)}>
        +5
      </button>
    </main>
  )
}

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <Counter />
  </StrictMode>,
)
```

The mounted component displays **Count: 0** and **+1** and **+5** buttons. Clicking either button calls `inc` with its amount, changes the selected count, and updates the displayed number. Click **+1**, then **+5**: the displayed count changes to `1`, then `6`. The action returns no value; read the result through the count selector.

## Update choices

Choose the update form according to where the next value comes from.

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| Object passed to `set` | Partial store state | No default; supply an update | Sets known field values and shallowly merges them into the existing object state. |
| Function passed to `set` | Current state → complete or partial store state | No default; supply an update | Computes the update from the current state, as `inc` does above. |
| Second argument to `set` | `boolean` | Merges when omitted for object updates | `false` merges; `true` replaces the state. See [replacement typing and precautions](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/type-stores-and-middleware). |

## Pitfalls

- Keep the previous-value calculation inside the functional updater so it reads the store value at the time of the call.
- For nested objects, follow [Update nested state](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/update-nested-state) and the merging rules in [State and actions](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/state-and-actions).
- To select several values as one object or array, follow [Selectors and subscriptions](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/selectors-and-subscriptions). This sample selects the count and action separately.

## Live demo

Try the [live counter demo](https://zustand-demo.pmnd.rs/). It uses the same functional increment pattern as the sample's **+1** button. Browse the [demo source](https://github.com/pmndrs/zustand/blob/d7a5583cffd80af515f7dfb69583c95cbdc9e2ce/examples/demo) or the [typed React starter](https://github.com/pmndrs/zustand/blob/d7a5583cffd80af515f7dfb69583c95cbdc9e2ce/examples/starter) for the original examples.

## Related

- [State and actions](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/state-and-actions) explains immutable updates and merging.
- [Split a store into slices](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/split-a-store-into-slices) keeps colocated state and actions modular as the store grows.
- [Use reducers and dispatch](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/use-reducers-and-dispatch) covers the alternative reducer pattern.
