intermediate
Selectors
Encapsulate reads, derive view models, and memoize expensive projections when inputs are stable.
Selectors encapsulate reads and derived projections from the store. Simple selectors read a slice; memoized selectors (reselect) recompute only when input slices change reference or value.
import { createSelector } from '@reduxjs/toolkit';
const selectTodos = (state) => state.todos;
const selectActiveTodos = createSelector([selectTodos], (todos) =>
todos.filter((t) => !t.done),
);
Colocate selectors with slices. View components should not know store shape — they call `selectCartTotal(state)` or `useSelector(selectCartTotal)`.
The trade-off is encapsulated reads and memoization versus memory for caches and complexity when inputs churn.
On interviews: when memoization helps versus adds overhead; how normalization shifts work to selectors.
Common pitfalls: inline arrow functions in `useSelector` creating new references every render, selectors that mutate state, and deriving in components instead of shared selectors.
Checklist:
- Encapsulate shape behind selectors.
- Memoize expensive joins and filters.
- Stable selector references to useSelector.
- Test selectors as pure functions.