DEV Community

Cover image for Why React Re-renders More Than Expected
Ravali Peddi
Ravali Peddi

Posted on

Why React Re-renders More Than Expected

Understanding React’s Reconciliation and Re-rendering Behavior

React’s rendering process can sometimes feel unpredictable. You might expect a component to re-render only when necessary, yet it updates more frequently than intended. Let’s break down why this happens and how to prevent unnecessary re-renders.

1. Re-renders Happen When State or Props Change

React components re-render when:

  • State changes via useState or useReducer.
  • Props change, even if the new value is the same as the previous one.
  • Parent re-renders, causing children to re-render as well.

Example: Unexpected re-render due to reference changes

const App = () => {
  const [count, setCount] = React.useState(0);
  const data = { value: 42 }; // New object created on each render

  return <Child data={data} />;
};
Enter fullscreen mode Exit fullscreen mode

Here, data is recreated on every render, causing Child to re-render even if count remains the same.

2. Functions as Props Cause Unnecessary Re-renders

Passing functions as props can lead to excessive re-renders because functions are recreated on every render.

Fix: Use useCallback

const App = () => {
  const [count, setCount] = React.useState(0);
  const handleClick = React.useCallback(() => setCount(c => c + 1), []);

  return <Child onClick={handleClick} />;
};
Enter fullscreen mode Exit fullscreen mode

useCallback ensures that handleClick is the same function reference between renders unless dependencies change.

3. Avoid Re-rendering with React.memo

React.memo prevents functional components from re-rendering if their props haven’t changed.

Example:

const Child = React.memo(({ value }) => {
  console.log("Child rendered");
  return <div>{value}</div>;
});
Enter fullscreen mode Exit fullscreen mode

This ensures Child only re-renders when value changes.

4. Derived State Can Cause Unintended Re-renders

Using computed values inside the component without memoization can lead to re-computation on every render.

Fix: Use useMemo

const expensiveCalculation = React.useMemo(() => computeHeavyTask(value), [value]);
Enter fullscreen mode Exit fullscreen mode

useMemo ensures that expensive calculations only run when value changes.

Final Thoughts

React’s reconciliation process is efficient, but excessive re-renders can hurt performance. Optimizing with useCallback, useMemo, and React.memo can significantly improve rendering efficiency.

Understanding these nuances ensures that your React apps run smoothly with minimal performance overhead.

Top comments (0)