When Does a React Component Re-render?

While working on a React-based dashboard for a U.S. retail analytics client, I noticed the app slowing down whenever users changed filters. After digging deeper, I realized the issue wasn’t the API; it was unnecessary component re-renders.

If you’ve ever seen your React app flicker or lag after a small update, this post is for you. I’ll walk you through exactly when and why React components re-render, how to identify performance bottlenecks, and how to prevent unwanted re-renders using practical examples.

Understand React Re-renders

In React, re-rendering means React calls the component function again to determine what the UI should look like after a change in state or props.

Every render produces a new React element tree, which React then compares (via the Virtual DOM) to the previous tree. If something changes, React updates the UI efficiently.

However, not all re-renders are necessary. Understanding what triggers them helps us optimize performance.

Method 1 – State Changes Trigger Re-renders

When a component’s state changes using the useState hook (or this.setState in class components), React re-renders that component.

Here’s a simple example:

import React, { useState } from "react";

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

  console.log("Component re-rendered!");

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h2>Current Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

export default Counter;

I executed the above example code and added the screenshot below.

When Does React Component Re-render

Every time you click the “Increase” button, the count state changes. React detects this change and re-renders the Counter component to reflect the new value.

If you open the console, you’ll see “Component re-rendered!” each time you click. That’s React doing its job.

Method 2 – Props Changes Cause Child Re-renders

When a parent component passes different props to a child, React re-renders that child—even if the change seems minor.

Here’s an example:

import React, { useState } from "react";

function Child({ name }) {
  console.log("Child re-rendered!");
  return <h3>Hello, {name}!</h3>;
}

function Parent() {
  const [name, setName] = useState("John");

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <Child name={name} />
      <button onClick={() => setName("Jane")}>Change Name</button>
    </div>
  );
}

export default Parent;

I executed the above example code and added the screenshot below.

When React Component Re-render

When the name prop changes from “John” to “Jane,” React re-renders both the parent and the child component because the child receives a new prop value.

This is one of the most common reasons for unexpected re-renders in React apps.

Method 3 – Parent Re-renders Affect Children

Even if a child’s props don’t change, it can still re-render if its parent re-renders.

Let’s see it in action:

import React, { useState } from "react";

function Child() {
  console.log("Child re-rendered!");
  return <h3>Child Component</h3>;
}

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

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increase</button>
      <Child />
    </div>
  );
}

export default Parent;

I executed the above example code and added the screenshot below.

When Does a React Component Re-render

Every time the parent’s state changes, React re-renders the parent, and by default, all its children too.

This is why developers often use memoization to prevent unnecessary re-renders in child components.

Method 4 – Use React.memo() to Prevent Unnecessary Re-renders

React.memo() is a higher-order component that tells React to skip re-rendering a component if its props haven’t changed.

Here’s how you can use it:

import React, { useState, memo } from "react";

const Child = memo(function Child({ name }) {
  console.log("Child re-rendered!");
  return <h3>Hello, {name}!</h3>;
});

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

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increase</button>
      <Child name={name} />
    </div>
  );
}

export default Parent;

I executed the above example code and added the screenshot below.

React Component Re-render

Now, when you click the “Increase” button, only the parent re-renders. The Chil component remains untouched because its props (name) haven’t changed.

This small optimization can significantly improve performance in large applications.

Method 5 – Avoid Inline Functions and Objects

React re-renders a child component if it receives a new reference for props like functions or objects, even if their content is the same.

Here’s an example of what not to do:

import React, { useState } from "react";

function Child({ onClick }) {
  console.log("Child re-rendered!");
  return <button onClick={onClick}>Click Me</button>;
}

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

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h2>Count: {count}</h2>
      <Child onClick={() => setCount(count + 1)} />
    </div>
  );
}

export default Parent;

Even if count doesn’t change, React creates a new function reference for onClick on every render, causing the child to re-render.

To fix this, we use the useCallback hook.

Method 6 – Use useCallback() to Stabilize Function References

useCallback() memoizes a function so that its reference remains the same between renders (unless its dependencies change).

Here’s the optimized version:

import React, { useState, useCallback } from "react";

function Child({ onClick }) {
  console.log("Child re-rendered!");
  return <button onClick={onClick}>Click Me</button>;
}

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

  const handleClick = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h2>Count: {count}</h2>
      <Child onClick={handleClick} />
    </div>
  );
}

export default Parent;

Now, the handleClick function reference stays the same across re-renders, preventing the child from re-rendering unnecessarily.

This is one of my go-to techniques when optimizing React applications.

Method 7 – Use useMemo() for Expensive Computations

Sometimes, a component re-renders because a parent has changed, but the child performs heavy calculations each time.

useMemo() helps cache the result of expensive computations.

import React, { useState, useMemo } from "react";

function ExpensiveComponent({ num }) {
  const result = useMemo(() => {
    console.log("Calculating...");
    let total = 0;
    for (let i = 0; i < 100000000; i++) total += i * num;
    return total;
  }, [num]);

  return <h3>Result: {result}</h3>;
}

function App() {
  const [num, setNum] = useState(1);
  const [count, setCount] = useState(0);

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <ExpensiveComponent num={num} />
      <button onClick={() => setNum(num + 1)}>Increase Num</button>
      <button onClick={() => setCount(count + 1)}>Increase Count</button>
    </div>
  );
}

export default App;

The ExpensiveComponent only recalculates when num changes, not when unrelated state (count) changes.

This makes your app faster and smoother, especially when handling large data computations.

Bonus Tip – Use React DevTools to Visualize Re-renders

If you’re unsure which components are re-rendering, the React DevTools Profiler is your best friend.

It shows which components re-render and how long each render takes. You can use this data to pinpoint performance issues and apply memoization strategically.

Re-renders are a natural part of React’s lifecycle, but unnecessary ones can slow your app down.

Here’s a quick summary of what we learned:

  • State and props changes trigger re-renders.
  • Parent re-renders can cascade to children.
  • Use React.memo(), useCallback(), and useMemo() to control re-renders.
  • Avoid inline functions and objects in props.
  • Use React DevTools to monitor performance.

By applying these techniques, you’ll not only make your React apps faster but also more predictable and scalable.

You may read:

Leave a Comment

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.