everything about frontend performance
Real examples on how you can improve your frontend performance and not your average use memo use callback explainer
Everything Frontend Performance
Hmm, let's make your frontend more performant! (And nah, this ain't a blog post that talks about useMemo
or useCallback
, chill.)
Identifying the Performance Bottleneck
Before optimizing anything, ask yourself: Which part of my frontend is slow? If you don't identify the bottleneck, you can't improve it.
Make React Profiler, Chrome DevTools and React DevTools (chrome extension) your best friend.
Common Frontend Performance Issues
1. UI Freezing or Lagging
Rendering large lists? Virtualization is your best friend.
- Don't map over an array of 10,000 items and render all at once.
- Use pagination or virtualization (e.g.,
react-window
orreact-virtualized
) to render only what's in the viewport.
2. Heavy Computation Blocking the Main Thread
JS is single-threaded. If you run expensive computations on the main thread, your UI will freeze.
Example 1: Blocking the main thread
const blockThread = () => {
const start = Date.now();
while (Date.now() - start < 3000) {
Math.random() * Math.random();
}
};
blockThread(); // UI is frozen for 3 seconds
Example 2: Offloading to Web Workers
Use Web Workers to move heavy computation off the main thread. read more Docs
const worker = new Worker("worker.js");
worker.postMessage("heavy-task");
worker.onmessage = (e) => console.log("Result:", e.data);
3. Caching Expensive Computations
Maintain a small cache (e.g., LRU cache) to store frequently accessed values instead of recomputing them.
const cache = new Map();
const getCachedValue = (key, computeFn) => {
if (cache.has(key)) return cache.get(key);
const result = computeFn();
cache.set(key, result);
return result;
};
4. Preventing Unnecessary Re-renders
Wrap components in React.memo
to prevent unnecessary re-renders due to parent state changes.
import React, { memo } from "react";
const AboutPage = memo(({ user, isAuthenticated }) => {
return <div>AboutPage</div>;
});
export default AboutPage;
Why? React re-renders components when the parent re-renders and if this AboutPage was used as a component in one of the parent components and on state change in parent component even AboutPage would re-render. Hence memo
prevents this unless the props change.
5. Improving First Contentful Paint (FCP)
Avoid blocking UI rendering by running expensive operations after the initial render.
import React, { useEffect } from "react";
const HomePage = () => {
useEffect(() => {
const blockThread = () => {
const start = Date.now();
while (Date.now() - start < 3000) {
Math.random() * Math.random();
}
};
blockThread(); // Freezes UI
}, []);
return <div>HomePage</div>;
};
export default HomePage;
Fix: Use Web Workers to defer non-essential operations.
6. Dynamic Imports for Reducing Bundle Size
If a library isn't needed on the first render, lazy load it dynamically.
import dynamic from "next/dynamic";
const HeavyComponent = dynamic(() => import("./HeavyComponent"), { ssr: false });
7. Tree Shaking
Ensure your bundler removes unused code from your final bundle.
// Instead of importing the entire lodash library:
import _ from "lodash";
console.log(_.debounce);
// Import only the required function:
import { debounce } from "lodash";
console.log(debounce);
Frontend Pitfalls & Oopsies
useEffect
Dependency Array Issues
Using objects or functions as dependencies in useEffect
causes unnecessary re-renders.
useEffect(() => {
// do something
}, [user]); // ❌ Bad: Objects have different references every time
useEffect(() => {
// do something
}, [user.id]); // ✅ Good: Use primitive values
JS compares object references, not values. Always use primitive values where possible.
Apply these techniques and make your frontend blazing fast!