Selectors & useShallow

Prevent unnecessary re-renders by selecting only the data your component needs.

State Management6 min readConcept 6 of 22

What are Selectors?

A selector is a function you pass to your Zustand hook to pick out a specific piece of state. By default, Zustand uses strict equality (===) to compare the return value of your selector with its previous value. If it changes, your component re-renders.

const bears = useStore((state) => state.bears);

The Object Literal Problem

If you need multiple values from the store, you might be tempted to return an object literal from your selector:

const { bears, fish } = useStore((state) => ({ bears: state.bears, fish: state.fish }));

Because JavaScript compares objects by reference, this creates a **new object** every time the store updates. This means your component will re-render every single time *anything* in the store changes, defeating Zustand's performance benefits.

Fixing it with `useShallow`

Zustand provides a useShallow helper to fix this. It tells Zustand to shallow-compare the keys of the object you return, rather than strictly comparing the object reference.

tsx import { useShallow } from 'zustand/react/shallow'; const { bears, fish } = useStore( useShallow((state) => ({ bears: state.bears, fish: state.fish })) );

Now, the component will only re-render if bears or fish actually changes.

Re-render Visualization

In this interactive lab, use the toolbar to update different parts of the store. Watch how components using proper selectors ignore updates they don't care about, while poorly configured components re-render pointlessly.

// ❌ Re-renders on ANY store change const { bears } = useStore((state) => ({ bears: state.bears })); // ✅ Only re-renders when 'bears' changes const { bears } = useStore(useShallow((state) => ({ bears: state.bears })));

Without useShallow

Object Literal

Bears: 0I re-render on EVERYTHING

With useShallow

Shallow Comparison

Bears: 0I only re-render for bears

Click increaseFish(). The bad component re-renders because it created a new object reference, even though 'bears' didn't change!

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1Why does returning an object from a Zustand selector cause unnecessary re-renders?

Remember this

  • Selectors allow components to subscribe to specific slices of state.
  • Returning object literals from selectors breaks strict equality checks.
  • Use useShallow from zustand/react/shallow when returning objects.
  • Calling useStore() without a selector subscribes to all state changes.

Done with this concept?

Mark it complete to track your progress. No login needed.