DEV Community

Cover image for ⚡ React-Redux Optimization: Common Mistakes That Trigger Unnecessary Rerenders
Raghuveer Bharadwaj
Raghuveer Bharadwaj

Posted on

⚡ React-Redux Optimization: Common Mistakes That Trigger Unnecessary Rerenders

If your Redux-connected React components are mysteriously rerendering like they’ve had five cups of coffee ☕ — chances are you're making one of these common but sneaky mistakes.

Let’s explore what not to do, why it causes performance issues, and the sharpest ways to fix it.


❌ 1. Destructuring Redux Objects Inside Components

const { name, email } = useSelector((state) => state.user); // ❌
Enter fullscreen mode Exit fullscreen mode

Looks clean, but this subscribes to the entire user object. So if any field inside user changes — even user.avatarUrl — your component rerenders.

🧠 Redux selectors use reference equality (===). Destructuring causes you to compare new objects every render.

✅ Instead, pick only the fields you need:

const name = useSelector((state) => state.user.name); // ✅
const email = useSelector((state) => state.user.email);
Enter fullscreen mode Exit fullscreen mode

❌ 2. Selecting the Whole Object, Then Accessing Inside

const user = useSelector((state) => state.user); // ❌
const name = user.name;
Enter fullscreen mode Exit fullscreen mode

Even though you're only using name, you've subscribed to the whole user object. Any change (e.g., password update, login status) triggers a rerender.

✅ Better:

const name = useSelector((state) => state.user.name); // ✅
Enter fullscreen mode Exit fullscreen mode

❌ 3. Pulling Unfiltered Data You Don’t Need

Let’s say you're rendering a widget layout:

const layout = [{ id: 'w1' }, { id: 'w3' }];
Enter fullscreen mode Exit fullscreen mode

Now:

const widgets = useSelector((state) => state.widgets); // ❌ bad idea
Enter fullscreen mode Exit fullscreen mode

You just subscribed to every widget in the store, even if your component only displays two.

✅ Fix: Filter only what’s relevant + use a custom equality function

const widgetsInLayout = useSelector(
  (state) => {
    const allWidgets = state.widgets;
    const ids = layout.map((l) => l.id);

    return ids.reduce((acc, id) => {
      if (allWidgets[id]) acc[id] = allWidgets[id];
      return acc;
    }, {});
  },
  (prev, next) => {
    const prevKeys = Object.keys(prev);
    const nextKeys = Object.keys(next);

    if (prevKeys.length !== nextKeys.length) return false;

    return prevKeys.every((key) => {
      return (
        prev[key]?.config === next[key]?.config &&
        prev[key]?.data === next[key]?.data
      );
    });
  }
);
Enter fullscreen mode Exit fullscreen mode

Now your component only rerenders when widgets used in the current layout actually change — not on every widget update.


❌ 4. Returning Objects in Selectors Without Equality Check

const userInfo = useSelector((state) => ({
  name: state.user.name,
  age: state.user.age,
})); // ❌ causes rerenders
Enter fullscreen mode Exit fullscreen mode

Even if values don’t change, this object is new on every render — causing unnecessary updates.

✅ Fix: Use shallow equality

import { shallowEqual, useSelector } from 'react-redux';

const userInfo = useSelector(
  (state) => ({
    name: state.user.name,
    age: state.user.age,
  }),
  shallowEqual // ✅ avoids rerenders if values don’t change
);
Enter fullscreen mode Exit fullscreen mode

❌ 5. Creating Selectors Inside Components

const selectUserName = (state) => state.user.name;

const MyComponent = () => {
  const name = useSelector(selectUserName); // ❌ Looks okay, but can re-run unnecessarily
}
Enter fullscreen mode Exit fullscreen mode

If the selector isn’t memoized or reused, it could lead to recomputation or unstable results across renders.


✅ TL;DR Cheat Sheet

❌ Don’t ✅ Do
Destructure full Redux slices Pick exact fields in useSelector
Return whole objects in selectors Return only required keys
Skip equality checks Use shallowEqual or custom compare
Create selectors inside components Define them outside
Pull entire state trees Filter context-specific slices only

🧠 Pro Tip: Always Think in Terms of React's Rerender Triggers

React only rerenders when props or state change. If you're feeding it fresh objects or large slices from Redux, you're making it think something has changed — even when it hasn't.

Keep your selectors pure, focused, and stable. Use tools like shallowEqual and custom equality checks only when needed, and never fetch more than you actually use.

With a little precision, your Redux-connected components will stay fast, predictable, and frustration-free. 🚀


📝 Disclaimer:
This post was assisted by AI (ChatGPT) for clarity and structure.


Top comments (0)