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.

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 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.

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.

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:
- Get Fetch Results in a React Functional Component
- How to Use Card Component in React JS?
- Build a React Text Editor Component
- Build a Reusable React Component with Generic Type

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.