Performance plays a vital role in developing modern React applications. React by default is developed by keeping performance in mind, it offers virtual DOM, efficient reconciliation, and a component-based architecture. But as application grows, we start facing performance issues. This blog will help you with some performance optimization tips to consider before release.
1. memo to Prevent Unnecessary Re-renders:
React.memo is a build in component memorization technic. When we wrap a component within React.memo, it shallowly compares previous and current props to avoid unnecessary re-renders. Since this comparison has a cost, it should be applied selectively rather than to every component.
Example:
const getEmployeeId= React.memo(({emp}) => {
return <div>{emp.empId }</div>;
});
Bonus Tip: Make use of useCallback (memorizes a function reference) and useMemo (memorizes a expensive computed value) hooks to prevent unnecessary re-renderings.
2. lazy to load component on demand:
React.lazy is to load component only on demand instead of including it in the initial JavaScript bundle. This is mainly useful, if it is a large application with many screens.
Example:
const UserProfile= React.lazy(() => import("./userProfile"));
Bonus Tip: Make use of < Suspense> to show fallback loading component, while the actual component loads. This gives better user experience.
<Suspense fallback={<Loader />}>
< UserProfile /></Suspense>
3. Avoid using array index as element key
Using proper stable and unique identifier is always important. Below are few examples which look harmless but have a serious performance impact.
{users.map((user, index) => (
<li key={index}> {user.name} </li>
))}
{ users.map(user => (
<li key={Math.random()} > {user.name} </li>
))}
This causes below performance issues:
- keys change every render
- React treats every item as new
- full list remounts on every update
Correct Usage:
{users.map((user) => (<li key={user.id}>{user.name}</li>
))}
4. Use Debounce & Throttle for expensive operations
When user activity interacts with applications like typing scrolling or dragging, multiple API calls can happen per second unintentionally. Debouncing and throttling are two core techniques used to limit how often these operations should be executed, hence help in improving the performance.
const getData = useCallback(
debounce((value) => {
axios.get(`https://api.sample.in/employee /${empId }`)
.then(response => {
console.log(response.data[0]);
});
}, 2000),
[]
);
In above example, the debounce function from Lodash is used to delay the API call until 2 seconds after every user interaction.
fromEvent(window, 'resize').pipe(
startWith(null),
throttleTime(2000, undefined, { leading: true, trailing: true }),
map(() => ({ w: window.innerWidth, h: window.innerHeight })),
takeUntilDestroyed(this.destroyRef)
).subscribe(({ w, h }) => {
this.width = w;
this.height = h;
});}
In the above example operation runs every 2000 milliseconds, even if event fire continuously (scroll, resize, dragging).
Conclusion:
React comes with devtools support which provides a Profiler tab. This helps us in understanding key area where performance dips. It gives a list of slow components, identifies wasted renders and real bottlenecks in applications. Start by identifying the performance issues, then address them with the appropriate solutions to build a super‑speed application. Happy learning! 🚀
Reference:
React Performance Optimization: 15 Best Practices for 2025 – DEV Community
React Optimization Techniques to Help You Write More Performant Code
