reduxjs/react-redux · warning
Selector ${selector.name || 'unknown'} returned a different
Error message
Selector ${selector.name || 'unknown'} returned a different result when called with the same parameters. This can lead to unnecessary rerenders.
Selectors that return a new reference (such as an object or an array) should be memoized: https://redux.js.org/usage/deriving-data-selectors#optimizing-selectors-with-memoization What it means
In development, react-redux's useSelector re-runs the selector with the last state/args and compares results to detect unstable selectors. This warning fires when a selector called with identical parameters returns a new reference (e.g. a fresh object or array) each call, which defeats reference-equality memoization in useSelector and causes unnecessary component re-renders on every store change.
Source
Thrown at src/hooks/useSelector.ts:199
} = {
stabilityCheck,
identityFunctionCheck,
...devModeChecks,
}
if (
finalStabilityCheck === 'always' ||
(finalStabilityCheck === 'once' && firstRun.current)
) {
const toCompare = selector(state)
if (!equalityFn(selected, toCompare)) {
let stack: string | undefined = undefined
try {
throw new Error()
} catch (e) {
// eslint-disable-next-line no-extra-semi
;({ stack } = e as Error)
}
console.warn(
'Selector ' +
(selector.name || 'unknown') +
' returned a different result when called with the same parameters. This can lead to unnecessary rerenders.' +
'\nSelectors that return a new reference (such as an object or an array) should be memoized: https://redux.js.org/usage/deriving-data-selectors#optimizing-selectors-with-memoization',
{
state,
selected,
selected2: toCompare,
stack,
},
)
}
}
if (
finalIdentityFunctionCheck === 'always' ||
(finalIdentityFunctionCheck === 'once' && firstRun.current)
) {
// @ts-ignoreView on GitHub (pinned to 16f1a91eb2)
Solutions
- Memoize the selector with reselect: const selectItems = createSelector([s => s.items], items => items.filter(i => i.done)) and pass that to useSelector.
- Return atomic/state slices directly instead of constructing new objects when possible.
- If the result is genuinely a new composite, pass an equality function: useSelector(selectResult, shallowEqual) (from react-redux or the shallowequal package).
- Keep expensive transformations (filter/map/sort) inside a memoized selector, not inline in useSelector unless inputs are stable.
- Only compute derived data via useSelector's memoized arguments pattern if using useReducer-style memoization is not enough — prefer createSelector.
Example fix
// before
const { a, b } = useSelector(state => ({ a: state.a, b: state.b }))
// after
import { createSelector } from 'reselect'
import { shallowEqual } from 'react-redux'
const selectAB = createSelector([s => s.a, s => s.b], (a, b) => ({ a, b }))
const { a, b } = useSelector(selectAB)
// or: useSelector(state => ({ a: state.a, b: state.b }), shallowEqual) Defensive patterns
Strategy: validation
Validate before calling
// Verify selector stability before wiring it up
function isStableSelector(selector, state, args) {
const a = selector(state, args)
const b = selector(state, args)
return a === b
}
// usage: if (!isStableSelector(selectVisibleItems, store.getState())) wrap in createSelector() Try / catch
null
Prevention
- Never build objects/arrays inline in useSelector without shallowEqual or reselect createSelector.
- Memoize derived selectors with createSelector and keep them outside components (module scope).
- Enable React StrictMode/react-redux dev warnings in CI and treat this console.warn as a failure (assert no console.warn in selector tests).
- Use createSelectorCreator with equalityCheck if non-reference equality is intended, or pass shallowEqual to useSelector.
- Keep filters/maps/sorts inside memoized selectors, not in render body or inline arrows.
When it happens
Trigger: A selector passed to useSelector returns a newly created object/array (e.g. state => ({a: state.a, b: state.b}) or state => state.items.filter(...)) with no memoization; useSelector with equalityFn left as default reference equality; selector depends on non-memoized derived data.
Common situations: Inline arrow selectors in useSelector building result objects; selectors using .map/.filter/.slice returning new arrays; upgrading react-redux (5.x era connect-style selectors moving to hooks) and hitting the new dev-time stability check; forgetting reselect's createSelector or shallowEqual.
Related errors
- Selector ${selector.name || 'unknown'} returned the root sta
- You must pass a selector to useSelector
- You must pass a function as a selector to useSelector
- You must pass a function as an equality function to useSelec
- Could not find "store" in the context of "${displayName}". E
AI-assisted analysis of reduxjs/react-redux@16f1a91eb2 (2026-08-31).
Data as JSON: /api/errors/ab9425c4542ae30e.
Report an issue: GitHub.