Redux & Redux Toolkit Course
Redux & Redux Toolkit
/
Advanced

Selector Performance

Definition

The study of how poorly written selectors can destroy React performance by forcing components to re-render even when the Redux state hasn't meaningfully changed.

Explain Like I'm New

`useSelector` uses strict equality (`===`) to check if data changed. If your selector returns a literal object `{}` or uses `.filter()`, it creates a NEW memory address every single time it runs. `useSelector` sees a new memory address, thinks the data changed, and forces your component to re-render, creating a devastating performance loop.

Real World Example

A component that uses `useSelector(state => state.items.filter(i => i.active))`. Every time ANY action is dispatched in the entire app, this component will needlessly re-render.

Common Use Cases

  • Fixing sluggish React apps
  • Profiling Redux DevTools

Interactive Example

// ❌ DISASTER: .map() creates a new array every time ANY state changes!
// The component will re-render constantly, killing performance.
const activeIds = useSelector(state => 
  state.todos.filter(t => t.active).map(t => t.id)
);

// ✅ FIX 1: Use a memoized selector (createSelector)
const activeIds = useSelector(selectActiveTodoIds);

// ✅ FIX 2: Use the shallowEqual comparison function
import { useSelector, shallowEqual } from 'react-redux';

const activeIds = useSelector(
  state => state.todos.filter(t => t.active).map(t => t.id), 
  shallowEqual // Tells Redux: 'Only re-render if the actual items inside the array changed'
);

Interview Questions

basic

  • Why is returning an object literal like `useSelector(state => { data: state.data })` a terrible idea?

intermediate

  • How does RTK's `shallowEqual` utility help with selector performance?

Flash Cards

Question

Why object literal bad?

Click to reveal answer
Answer

Because `{}` always creates a brand new object in memory. Redux compares the old object to the new object, sees they have different memory addresses, and forces a re-render.

Question

shallowEqual?

Click to reveal answer
Answer

You can pass `shallowEqual` as a second argument to `useSelector`. It tells Redux to check the contents of the object (`obj.a === obj.a`), rather than just checking the memory address. This prevents the unnecessary re-render.