# Selectors and Avoiding Re-renders — Redux Toolkit / Zustand

Source: https://www.skillbyai.com/en/redux-zustand/z-select

> Pick small values; use useShallow for objects.

## Reference equality decides

A component re-renders when its selector's result changes. Calling the hook with no selector subscribes to the whole store, so the component re-renders on every change. Select primitives or stable references where possible. A selector that builds a new object or array (`(s) => ({ a: s.a, b: s.b })`) returns a new reference every time; in Zustand 5 this can trigger an infinite update loop error. Wrap such selectors in `useShallow`, which compares the result shallowly and returns the previous reference when nothing changed.

## Good and bad selectors

useShallow for multi-value picks.

```tsx
import { useShallow } from 'zustand/react/shallow';

// re-renders on any change to the store
const everything = useCart();

// fine: a primitive
const count = useCart((s) => s.items.length);

// fine: actions are stable references
const add = useCart((s) => s.add);

// new object each time -> wrap with useShallow
const { items, clear } = useCart(useShallow((s) => ({ items: s.items, clear: s.clear })));

// new array each time -> also wrap
const ids = useCart(useShallow((s) => s.items.map((i) => i.id)));
```

## Export custom hooks

Exporting small hooks such as `useCartCount = () => useCart((s) => s.items.length)` keeps selectors consistent and stops components from subscribing to the whole store by accident.

**Quiz:** Why wrap (s) => ({ a: s.a, b: s.b }) in useShallow?

- [ ] Selectors cannot return objects at all
- [ ] useShallow makes the store persist
- [x] The selector returns a new object every call, so it needs shallow comparison
- [ ] It converts the store to Redux

*Answer:* The selector returns a new object every call, so it needs shallow comparison. Shallow comparison keeps the previous reference when values are equal.
