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

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.