π€― Introduction
When I began using React, I was obsessed with making things work β not making them fast. Over time, I noticed lags, unnecessary re-renders, and slow UI. Thatβs when I dove deep into performance and found gold.
In this post, Iβll share React performance optimization tips I wish I knew earlier, so you can skip the slowdowns and jump straight to building snappy apps.
βοΈ 1. Use React.memo
Smartly
React re-renders components even if the props havenβt changed β unless you wrap them in React.memo
.
const Button = React.memo(({ onClick, children }) => { console.log("Button rendered"); return <button onClick={onClick}>{children}</button>; });
β
Use it for pure components receiving primitive props.
β Donβt overuse β memo itself has an overhead.
π§ 2. Optimize with useCallback
& useMemo
Prevent unnecessary re-renders or recalculations.
const handleClick = useCallback(() => { console.log("Clicked!"); }, []);
const expensiveValue = useMemo(() => { return computeHeavyStuff(data); }, [data]);
These hooks keep references stable and prevent child components from rerendering.
π₯ 3. Avoid Inline Functions & Objects in JSX
Inline functions get recreated on every render:
// β Triggers re-renders <MyComponent onClick={() => doSomething()} /> // β
Better with useCallback const handleClick = useCallback(() => doSomething(), []); <MyComponent onClick={handleClick} />
Same applies to style={{}}
and inline objects.
π¦ 4. Code-Splitting with React.lazy
& Suspense
Donβt ship your entire app upfront.
const Settings = React.lazy(() => import('./Settings')); <Suspense fallback={<Loader />}> <Settings /> </Suspense>
π Keeps bundle size small
π Faster initial page load
π§Ή 5. Clean Up useEffect
Side Effects
Uncleared intervals or subscriptions lead to memory leaks.
useEffect(() => { const id = setInterval(doSomething, 1000); return () => clearInterval(id); }, []);
Always clean up effects when using timers, listeners, or subscriptions.
π 6. Avoid Unnecessary Re-renders
Use tools like:
why-did-you-render
- React DevTools Profiler
// Development only import whyDidYouRender from '@welldone-software/why-did-you-render'; if (process.env.NODE_ENV === 'development') { whyDidYouRender(React); }
These help you see whatβs rerendering and why.
π’ 7. Virtualize Long Lists
Rendering hundreds of DOM nodes? Thatβs slow.
Use react-window
or react-virtualized
:
import { FixedSizeList as List } from 'react-window'; <List height={400} itemCount={1000} itemSize={35} width={300}> {({ index, style }) => <div style={style}>Item {index}</div>} </List>
Only renders visible items. Huge performance gain.
π§― 8. Debounce Expensive Updates
Avoid re-rendering on every keystroke.
const debouncedSearch = useMemo(() => debounce(handleSearch, 300), []);
Use:
lodash.debounce
-
use-debounce
(React hook)
π‘ 9. Bonus Quick Wins
- Error Boundaries Prevent the entire UI from crashing:
class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { return this.state.hasError ? <Fallback /> : this.props.children; } }
- Skeleton Loaders Improve perceived performance:
<div className="h-6 w-full bg-gray-300 animate-pulse" />
- Intersection Observer with useRef Lazy load components only when in view.
const ref = useRef(); useEffect(() => { const observer = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) { // Trigger load } }); if (ref.current) observer.observe(ref.current); }, []);
π― Final Thoughts
React is powerful, but without understanding how rendering works, itβs easy to make your UI sluggish.
The key is to be intentional: Measure β Identify β Optimize.
I hope these tips help you build smoother, faster, and more efficient React apps!
Top comments (0)