React Performance Optimization: Advanced Techniques for Lightning-Fast Apps
React is powerful, but poorly optimized React apps can feel sluggish. Learn proven techniques to make your React applications blazingly fast with code splitting, memoization, virtualization, and more.
Measuring Performance
Before optimizing, measure your app's current performance.
React DevTools Profiler
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Wrapspan> components to profilespan>2<<span class="text-yellow-<span class="text-orange-400">300span>">Profilerspan> id=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">MyComponentspan>"span> onRender={onRenderCallback}>3 <<span class="text-yellow-<span class="text-orange-400">300span>">MyComponentspan> />4<span class="text-yellow-<span class="text-orange-400">300span>">Profilerspan>>Web Vitals
- **LCP (Largest Contentful Paint)**: < 2.5s
- **FID (First Input Delay)**: < 100ms
- **CLS (Cumulative Layout Shift)**: < 0.1
Lighthouse Audits
Run in Chrome DevTools for comprehensive performance analysis.
Code Splitting
Split your bundle to load only what's needed.
Dynamic Imports
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Beforespan>: <span class="text-yellow-<span class="text-orange-400">300span>">Loadsspan> entire <span class="text-yellow-<span class="text-orange-400">300span>">Dashboardspan> upfrontspan>2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> <span class="text-yellow-<span class="text-orange-400">300span>">Dashboardspan> <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./<span class="text-yellow-<span class="text-orange-400">300span>">Dashboardspan>'span>;3 4<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Afterspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Loadsspan> only when neededspan>5<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">Dashboardspan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./<span class="text-yellow-<span class="text-orange-400">300span>">Dashboardspan>'span>));6 7<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">Appspan>() {8 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (9 <<span class="text-yellow-<span class="text-orange-400">300span>">Suspensespan> fallback={<<span class="text-yellow-<span class="text-orange-400">300span>">LoadingSpinnerspan> />}>10 <<span class="text-yellow-<span class="text-orange-400">300span>">Dashboardspan> />11 <span class="text-yellow-<span class="text-orange-400">300span>">Suspensespan>>12 );13}Route-Based Splitting
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">Homespan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./pages/<span class="text-yellow-<span class="text-orange-400">300span>">Homespan>'span>));2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">Aboutspan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./pages/<span class="text-yellow-<span class="text-orange-400">300span>">Aboutspan>'span>));3<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">Productsspan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./pages/<span class="text-yellow-<span class="text-orange-400">300span>">Productsspan>'span>));4 5<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">Appspan>() {6 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (7 <<span class="text-yellow-<span class="text-orange-400">300span>">Suspensespan> fallback={<<span class="text-yellow-<span class="text-orange-400">300span>">PageLoaderspan> />}>8 <<span class="text-yellow-<span class="text-orange-400">300span>">Routesspan>>9 <<span class="text-yellow-<span class="text-orange-400">300span>">Routespan> path=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/"span> element={<<span class="text-yellow-<span class="text-orange-400">300span>">Homespan> />} />10 <<span class="text-yellow-<span class="text-orange-400">300span>">Routespan> path=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/about"span> element={<<span class="text-yellow-<span class="text-orange-400">300span>">Aboutspan> />} />11 <<span class="text-yellow-<span class="text-orange-400">300span>">Routespan> path=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/products"span> element={<<span class="text-yellow-<span class="text-orange-400">300span>">Productsspan> />} />12 <span class="text-yellow-<span class="text-orange-400">300span>">Routesspan>>13 <span class="text-yellow-<span class="text-orange-400">300span>">Suspensespan>>14 );15}Result: Initial bundle size reduced by 60-80%.
Memoization
Prevent unnecessary re-renders with memoization.
React.memo
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Expensivespan> component that doesn't need to re-renderspan>2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">ExpensiveComponentspan> = <span class="text-yellow-<span class="text-orange-400">300span>">Reactspan>.<span class="text-blue-400">memospan>(({ data }) => {3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> <div>{/* <span class="text-yellow-<span class="text-orange-400">300span>">Complexspan> rendering */}div>;4});5 6<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Onlyspan> re-renders <span class="text-purple-<span class="text-orange-400">400span> font-semibold">ifspan> data changesspan>useMemo Hook
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">ProductListspan>({ products }) {2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Expensivespan> calculationspan>3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> sortedProducts = <span class="text-blue-400">useMemospan>(() => {4 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> products.<span class="text-blue-400">sortspan>((a, b) => b.price - a.price);5 }, [products]); <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Onlyspan> recalculate when products changespan>6 7 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> <div>{sortedProducts.<span class="text-blue-400">mapspan>(...)}div>;8}useCallback Hook
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">Parentspan>() {2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Functionspan> is recreated on every renderspan>3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> handleClick = <span class="text-blue-400">useCallbackspan>(() => {4 console.<span class="text-blue-400">logspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-yellow-<span class="text-orange-400">300span>">Clickedspan>'span>);5 }, []); <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Functionspan> stable across rendersspan>6 7 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> <<span class="text-yellow-<span class="text-orange-400">300span>">ChildComponentspan> onClick={handleClick} />;8}Virtualization
Render only visible items in long lists.
React Virtual
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> { useVirtual } <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'react-virtual'span>;2 3<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">VirtualListspan>({ items }) {4 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> parentRef = <span class="text-blue-400">useRefspan>();5 6 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> rowVirtualizer = <span class="text-blue-400">useVirtualspan>({7 size: items.length,8 parentRef,9 estimateSize: <span class="text-blue-400">useCallbackspan>(() => <span class="text-orange-400">50span>, []),10 });11 12 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (13 <div ref={parentRef} style={{ height: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'500px'span>, overflow: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'auto'span> }}>14 <div style={{ height: rowVirtualizer.totalSize + <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'px'span> }}>15 {rowVirtualizer.virtualItems.<span class="text-blue-400">mapspan>(virtualRow => (16 <div17 key={virtualRow.index}18 style={{19 position: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'absolute'span>,20 top: <span class="text-orange-400">0span>,21 left: <span class="text-orange-400">0span>,22 width: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-orange-400">100span>%'span>,23 transform: <span class="text-blue-400">translateYspan>(virtualRow.start)px,24 }}25 >26 {items[virtualRow.index]}27 div>28 ))}29 div>30 div>31 );32}Performance: 10,000 item list renders in < 50ms instead of 5+ seconds.
Image Optimization
Images are often the largest assets.
Next.js Image Component
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> <span class="text-yellow-<span class="text-orange-400">300span>">Imagespan> <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'next/image'span>;2 3<<span class="text-yellow-<span class="text-orange-400">300span>">Imagespan>4 src=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/product.jpg"span>5 width={<span class="text-orange-400">500span>}6 height={<span class="text-orange-400">300span>}7 alt=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Productspan>"span>8 loading=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"lazy"span>9 placeholder=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"blur"span>10 blurDataURL=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"data:image/png;base64,..."span>11/>- Automatic format selection (WebP, AVIF)
- Responsive images
- Lazy loading
- Blur placeholder
Manual Lazy Loading
1<img 2 src=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"image.jpg"span> 3 loading=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"lazy"span> 4 decoding=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-purple-<span class="text-orange-400">400span> font-semibold">asyncspan>"span>5 alt=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Descriptionspan>"span>6/>Bundle Analysis
Identify what's bloating your bundle.
1# <span class="text-yellow-<span class="text-orange-400">300span>">Installspan> bundle analyzer2npm install --save-dev webpack-bundle-analyzer3 4# <span class="text-yellow-<span class="text-orange-400">300span>">Analyzespan>5npm run build -- --analyze- Moment.js (huge locales): Use day.js instead
- Lodash (entire library): Import specific functions
- Large icon libraries: Use tree-shaking
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Badspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Importsspan> entire <span class="text-blue-400">libraryspan>(500KB)span>2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> _ <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'lodash'span>;3 4<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Goodspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Importsspan> only what you <span class="text-blue-400">needspan>(5KB)span>5<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> debounce <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'lodash/debounce'span>;State Management Optimization
Context API Optimization
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Problemspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Entirespan> tree re-renders when any value changesspan>2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">AppContextspan> = <span class="text-blue-400">createContextspan>();3 4<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Solutionspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Splitspan> contexts by concernspan>5<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">UserContextspan> = <span class="text-blue-400">createContextspan>();6<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">ThemeContextspan> = <span class="text-blue-400">createContextspan>();7<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">SettingsContextspan> = <span class="text-blue-400">createContextspan>();8 9<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Usespan> selectors with <span class="text-yellow-<span class="text-orange-400">300span>">Zustandspan> or <span class="text-yellow-<span class="text-orange-400">300span>">Reduxspan>span>10<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> userName = <span class="text-blue-400">useStorespan>(state => state.user.name);Zustand (Lightweight State)
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> create <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'zustand'span>;2 3<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> useStore = <span class="text-blue-400">createspan>((set) => ({4 count: <span class="text-orange-400">0span>,5 increment: () => <span class="text-blue-400">setspan>((state) => ({ count: state.count + <span class="text-orange-400">1span> })),6}));7 8<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Onlyspan> re-renders when count changesspan>9<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">Counterspan>() {10 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> count = <span class="text-blue-400">useStorespan>((state) => state.count);11 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> increment = <span class="text-blue-400">useStorespan>((state) => state.increment);12 13 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> <button onClick={increment}>{count}button>;14}Debouncing and Throttling
Limit expensive operations.
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan> { useDebouncedCallback } <span class="text-purple-<span class="text-orange-400">400span> font-semibold">fromspan> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'use-debounce'span>;2 3<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">SearchBoxspan>() {4 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> [searchTerm, setSearchTerm] = <span class="text-blue-400">useStatespan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">''span>);5 6 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> debouncedSearch = <span class="text-blue-400">useDebouncedCallbackspan>(7 (value) => {8 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Expensivespan> <span class="text-yellow-<span class="text-orange-400">300span>">APIspan> callspan>9 <span class="text-blue-400">searchAPIspan>(value);10 },11 <span class="text-orange-400">500span> <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Waitspan> 500ms after user stops typingspan>12 );13 14 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (15 <input16 value={searchTerm}17 onChange={(e) => {18 <span class="text-blue-400">setSearchTermspan>(e.target.value);19 <span class="text-blue-400">debouncedSearchspan>(e.target.value);20 }}21 />22 );23}Concurrent Features (React 18+)
useTransition
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">SearchResultsspan>() {2 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> [isPending, startTransition] = <span class="text-blue-400">useTransitionspan>();3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> [query, setQuery] = <span class="text-blue-400">useStatespan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">''span>);4 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> [results, setResults] = <span class="text-blue-400">useStatespan>([]);5 6 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-blue-400">handleChangespan>(e) {7 <span class="text-blue-400">setQueryspan>(e.target.value);8 9 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Markspan> expensive update as low priorityspan>10 <span class="text-blue-400">startTransitionspan>(() => {11 <span class="text-blue-400">setResultsspan>(<span class="text-blue-400">expensiveFilterspan>(data, e.target.value));12 });13 }14 15 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (16 <>17 <input value={query} onChange={handleChange} />18 {isPending ? <<span class="text-yellow-<span class="text-orange-400">300span>">Spinnerspan> /> : <<span class="text-yellow-<span class="text-orange-400">300span>">Listspan> items={results} />}19 >20 );21}useDeferredValue
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">Appspan>() {2 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> [input, setInput] = <span class="text-blue-400">useStatespan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">''span>);3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> deferredInput = <span class="text-blue-400">useDeferredValuespan>(input);4 5 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// input updates <span class="text-blue-400">immediatelyspan>(responsive)span>6 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// deferredInput updates <span class="text-blue-400">laterspan>(when browser has time)span>7 8 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (9 <>10 <input value={input} onChange={(e) => <span class="text-blue-400">setInputspan>(e.target.value)} />11 <<span class="text-yellow-<span class="text-orange-400">300span>">ExpensiveListspan> query={deferredInput} />12 >13 );14}Advanced Patterns
Component Lazy Loading
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Loadspan> heavy components only when neededspan>2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">Chartspan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./<span class="text-yellow-<span class="text-orange-400">300span>">Chartspan>'span>));3<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">VideoPlayerspan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./<span class="text-yellow-<span class="text-orange-400">300span>">VideoPlayerspan>'span>));4<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> <span class="text-yellow-<span class="text-orange-400">300span>">RichTextEditorspan> = <span class="text-blue-400">lazyspan>(() => <span class="text-purple-<span class="text-orange-400">400span> font-semibold">importspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'./<span class="text-yellow-<span class="text-orange-400">300span>">RichTextEditorspan>'span>));Intersection Observer
Load content when visible:
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">LazyComponentspan>() {2 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> [isVisible, setIsVisible] = <span class="text-blue-400">useStatespan>(false);3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> ref = <span class="text-blue-400">useRefspan>();4 5 <span class="text-blue-400">useEffectspan>(() => {6 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> observer = new <span class="text-yellow-<span class="text-orange-400">300span>">IntersectionObserverspan>(([entry]) => {7 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">ifspan> (entry.isIntersecting) {8 <span class="text-blue-400">setIsVisiblespan>(true);9 observer.<span class="text-blue-400">disconnectspan>();10 }11 });12 13 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">ifspan> (ref.current) {14 observer.<span class="text-blue-400">observespan>(ref.current);15 }16 17 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> () => observer.<span class="text-blue-400">disconnectspan>();18 }, []);19 20 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> (21 <div ref={ref}>22 {isVisible ? <<span class="text-yellow-<span class="text-orange-400">300span>">ExpensiveComponentspan> /> : <<span class="text-yellow-<span class="text-orange-400">300span>">Placeholderspan> />}23 div>24 );25}Web Workers
Offload heavy computation:
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// worker.jsspan>2self.<span class="text-blue-400">addEventListenerspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'message'span>, (e) => {3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> result = <span class="text-blue-400">expensiveCalculationspan>(e.data);4 self.<span class="text-blue-400">postMessagespan>(result);5});6 7<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Componentspan>span>8<span class="text-purple-<span class="text-orange-400">400span> font-semibold">functionspan> <span class="text-yellow-<span class="text-orange-400">300span>">HeavyComputationspan>() {9 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> workerRef = <span class="text-blue-400">useRefspan>();10 11 <span class="text-blue-400">useEffectspan>(() => {12 workerRef.current = new <span class="text-yellow-<span class="text-orange-400">300span>">Workerspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'/worker.js'span>);13 14 workerRef.current.onmessage = (e) => {15 console.<span class="text-blue-400">logspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-yellow-<span class="text-orange-400">300span>">Resultspan>:'span>, e.data);16 };17 18 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> () => workerRef.current.<span class="text-blue-400">terminatespan>();19 }, []);20 21 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> compute = () => {22 workerRef.current.<span class="text-blue-400">postMessagespan>(largeDataset);23 };24 25 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> <button onClick={compute}><span class="text-yellow-<span class="text-orange-400">300span>">Calculatespan>button>;26}Performance Checklist
- [x] Code splitting by route
- [x] Lazy load heavy components
- [x] Tree-shake unused code
- [x] Analyze bundle size
- [x] Use production build
- [x] React.memo for expensive components
- [x] useMemo for expensive calculations
- [x] useCallback for stable functions
- [x] Virtualize long lists
- [x] Avoid inline objects/arrays in JSX
- [x] Lazy load images
- [x] Use modern formats (WebP, AVIF)
- [x] Responsive images
- [x] Compress assets
- [x] CDN for static files
- [x] API request caching
- [x] Prefetch critical resources
- [x] Debounce user input
- [x] Pagination for large datasets
- [x] GraphQL over REST (when beneficial)
- [x] Track Core Web Vitals
- [x] Lighthouse CI in pipeline
- [x] Real User Monitoring (RUM)
- [x] Error tracking (Sentry)
Real-World Results
- Initial load: 8.5s → 1.2s (86% faster)
- Bundle size: 2.4MB → 380KB (84% smaller)
- Techniques: Code splitting, image optimization, lazy loading
- List rendering: 5s → 45ms (99% faster)
- Technique: Virtualization for 10,000 item list
- Time to Interactive: 4.2s → 1.8s (57% faster)
- Techniques: Code splitting, useMemo, lazy images
Common Mistakes
- 1Premature optimization: Measure first, optimize bottlenecks
- 2Over-memoization: Not every component needs React.memo
- 3Large Context: Split contexts by concern
- 4Inline functions in JSX: Usually fine, profile before changing
- 5Not using production build: Development mode is 10x slower
Tools & Resources
- Chrome DevTools
- React DevTools Profiler
- Lighthouse
- WebPageTest
- Bundle Analyzer
- React Virtual (list virtualization)
- react-window (alternative virtualization)
- use-debounce (debouncing hooks)
- Zustand (lightweight state)
Conclusion
React performance optimization is about making strategic decisions: 1. Measure performance with Profiler and Lighthouse 2. Identify bottlenecks (don't guess) 3. Apply appropriate techniques (code splitting, memoization, virtualization) 4. Measure improvements 5. Iterate
Start with low-hanging fruit: code splitting and image optimization. These provide the biggest gains with minimal effort. Then tackle rendering performance with memoization and virtualization for long lists.
Remember: A fast app is a better user experience, better SEO rankings, and higher conversion rates. Every 100ms improvement in load time correlates with 1% increase in conversions.
Don't optimize everything—optimize what matters. Your users will thank you.