0
0
ReactDebug / FixBeginner · 4 min read

How to Prevent Unnecessary Re-renders in React Components

To prevent unnecessary re-renders in React, use React.memo to memoize components, and useCallback or useMemo hooks to memoize functions and values passed as props. This stops React from re-rendering components when their props or state have not changed.
🔍

Why This Happens

React re-renders components whenever their parent re-renders or their state changes. If you pass new objects or functions as props every time, React thinks the props changed and re-renders the child even if the data is the same.

This causes extra work and can slow down your app.

jsx
import React, { useState } from 'react';

function Child({ onClick }) {
  console.log('Child rendered');
  return <button onClick={onClick}>Click me</button>;
}

function Parent() {
  const [count, setCount] = useState(0);

  // This function is recreated on every render
  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <Child onClick={handleClick} />
    </div>
  );
}

export default Parent;
Output
Child rendered Child rendered Child rendered ... (every time Parent renders)
🔧

The Fix

Wrap the child component with React.memo to memoize it and prevent re-render if props are the same. Use useCallback to memoize the function so it does not get recreated on every render.

jsx
import React, { useState, useCallback } from 'react';

const Child = React.memo(function Child({ onClick }) {
  console.log('Child rendered');
  return <button onClick={onClick}>Click me</button>;
});

function Parent() {
  const [count, setCount] = useState(0);

  // useCallback memoizes the function
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, [setCount]);

  return (
    <div>
      <p>Count: {count}</p>
      <Child onClick={handleClick} />
    </div>
  );
}

export default Parent;
Output
Child rendered Child rendered Child rendered ... (only when count changes)
🛡️

Prevention

To avoid unnecessary re-renders in the future:

  • Use React.memo for functional components that receive props.
  • Memoize callback functions with useCallback when passing them as props.
  • Memoize expensive computed values with useMemo.
  • Avoid creating new objects or arrays inline in JSX props.
  • Use linting tools like eslint-plugin-react-hooks to catch missing dependencies.
⚠️

Related Errors

Similar issues include:

  • Stale closures: Functions capturing old state if dependencies are missing in useCallback.
  • Excessive re-renders: Caused by updating state in parent unnecessarily.
  • Prop drilling: Passing props through many layers can cause many re-renders; consider context or state management.

Key Takeaways

Use React.memo to memoize components and avoid re-render when props don't change.
Memoize functions passed as props with useCallback to keep their identity stable.
Memoize expensive values with useMemo to prevent recalculations and re-renders.
Avoid creating new objects or functions inline in JSX props.
Use linting tools to ensure hooks dependencies are correctly specified.