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-ignore

View on GitHub (pinned to 16f1a91eb2)

Solutions

  1. Memoize the selector with reselect: const selectItems = createSelector([s => s.items], items => items.filter(i => i.done)) and pass that to useSelector.
  2. Return atomic/state slices directly instead of constructing new objects when possible.
  3. If the result is genuinely a new composite, pass an equality function: useSelector(selectResult, shallowEqual) (from react-redux or the shallowequal package).
  4. Keep expensive transformations (filter/map/sort) inside a memoized selector, not inline in useSelector unless inputs are stable.
  5. 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

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


AI-assisted analysis of reduxjs/react-redux@16f1a91eb2 (2026-08-31). Data as JSON: /api/errors/ab9425c4542ae30e. Report an issue: GitHub.