# Selector subscriptions

A selector defines the value a component subscribes to, and Zustand re-renders that component when the selected value changes. Use a selector for the smallest state value the component needs; wrap a computed object or array selector with [`useShallow`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand-react-shallow#useshallow) when its contents can stay shallowly equal while the selector creates a new reference.

## How selection controls rendering

The store can change while a component's selected value stays the same. Zustand compares selector results with `Object.is` by default, so a primitive selection such as a number or string does not change when an unrelated field changes. A selector that constructs a new object or array produces a different reference, even when its entries are unchanged. `useShallow` keeps the previous result when the new result is shallowly equal.

```mermaid
flowchart LR
  A["Store update"] --> B["Run component selector"]
  B --> C{"Object.is: same result?"}
  C -->|Yes| D["Keep current render"]
  C -->|No| E["Re-render component"]
  B --> F["useShallow selector"]
  F --> G{"Shallowly equal?"}
  G -->|Yes| D
  G -->|No| E
```

Selecting the whole store subscribes a component to all store updates. Selecting an atomic value narrows that subscription. When you need a computed selection, `useShallow` handles arrays or objects whose top-level contents are unchanged; it does not make nested values deeply equal.

## Keep a computed selection stable

This mounted React example renders the bear names and Papa Bear's meal separately. Clicking the button changes the meal: the meal display updates, while the names selection remains shallowly equal and its component does not need to re-render.

Install Zustand and React, including React DOM for the mounted example:

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

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

type Meals = {
  papaBear: string
  mamaBear: string
  littleBear: string
}

type Store = {
  meals: Meals
  changePapaBearMeal: () => void
}

const useMeals = create<Store>((set) => ({
  meals: {
    papaBear: 'large porridge-pot',
    mamaBear: 'middle-size porridge pot',
    littleBear: 'A little, small, wee pot',
  },
  changePapaBearMeal: () =>
    set((state) => ({
      meals: { ...state.meals, papaBear: 'a large pizza' },
    })),
}))

function BearNames() {
  const names = useMeals(useShallow((state) => Object.keys(state.meals)))

  return <p>Bear names: {names.join(', ')}</p>
}

function PapaBearMeal() {
  const meal = useMeals((state) => state.meals.papaBear)

  return <p>Papa Bear's meal: {meal}</p>
}

function App() {
  const changePapaBearMeal = useMeals((state) => state.changePapaBearMeal)

  return (
    <main>
      <BearNames />
      <PapaBearMeal />
      <button onClick={changePapaBearMeal}>Change Papa Bear's meal</button>
    </main>
  )
}

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

Add `<div id="root"></div>` to the page that loads this entry point. Before the click, the page shows the three names and Papa Bear's porridge-pot meal. After the click, the meal text changes to pizza; the names stay the same. The names selector creates a fresh key array after the store update, but its entries are unchanged, so `useShallow` returns the previous array reference and prevents an unnecessary render of `BearNames`. The meal selector returns a different string, so `PapaBearMeal` updates.

## When to use shallow comparison

Use [`create`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand#create) to create the store hook, then select a value inside each component. Prefer direct selections for individual primitives or stable action references. Reach for `useShallow` when one component needs several values as an object or array, or a computed result such as `Object.keys(state.meals)`, and the top-level contents may remain equal across store updates.

Avoid an allocating selector without `useShallow` when stable output matters: in v5 a selector that returns a new reference can trigger unnecessary renders and may cause an infinite loop. See [Select state efficiently](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/select-state-efficiently) for that pitfall and other selector patterns. For immutable updates, see [Update nested state](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/update-nested-state); mutating a prior state object does not notify subscribers as an immutable update does.

For a comparison outside a component subscription, [`shallow`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand-shallow#shallow) returns whether two values are shallowly equal; it is not the component hook's equality-argument API. In v5, `create` does not accept a custom equality function. Use `useShallow` for the shallow-equality case rather than passing a second comparator to the store hook.

## See it running

The [Zustand live demo](https://zustand-demo.pmnd.rs/) shows a store-backed interface in the browser. For the authors' focused selector example, see [Prevent rerenders with `useShallow`](https://zustand.docs.pmnd.rs/learn/guides/prevent-rerenders-with-use-shallow).

## Related

- [How Zustand works](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/how-zustand-works)
- [Select state efficiently](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/select-state-efficiently)
- [Update nested state](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/update-nested-state)
