
James Miller
Published October 18, 2024

Deep dive into rendering optimization, memoization strategies, and profiling tools to make your apps faster.
React apps grow fast — and so do performance problems.
A component that renders 10 times per second? A list with 10,000 items? A bundle over 2MB?
Premature optimization is the root of all evil.
But measured, targeted optimization is pure magic.
Let's master the real tools that make React apps blazing fast.
React re-renders a component when:
Even if nothing visually changes.
<Parent> <ExpensiveChild data={hugeArray} /></Parent>→ ExpensiveChild re-renders every time Parent updates, even if hugeArray never changes.
Wrap functional components to skip re-renders when props are shallow-equal.
const ExpensiveChild = React.memo(function ExpensiveChild({ data }) { console.log('ExpensiveChild rendered'); return <HeavyChart data={data} />;});// Only re-renders if `data` reference changesWarning: Don't memo everything.
Memoization has memory + comparison cost.
→ Profile first!
| Hook | Caches | Use When |
|---|---|---|
| useMemo | Values (arrays, objects, calculations) | Expensive computation |
| useCallback | Functions | Passed to child components or useEffect |
const filteredUsers = useMemo(() => {return users.filter(user => user.active && user.role === 'admin');}, [users]);const handleSave = useCallback(() => {saveUser(user);}, [user]); // Prevents child re-renderreturn <Form onSave={handleSave} />;A 3MB bundle? Users wait.
Split it!
React.lazyconst HeavyChart = React.lazy(() => import('./HeavyChart'));const Dashboard = React.lazy(() => import('./Dashboard'));function App() {return ( <Suspense fallback={<Spinner />}> <HeavyChart /> </Suspense>);}Next.js bonus:
dynamic(() => import(...), { ssr: false })
Don't render 10,000 list items.
Render only what's visible.
react-windowimport { FixedSizeList } from 'react-window';<FixedSizeList height={600} itemCount={10000} itemSize={50} width="100%"> {({ index, style }) => ( <div style={style}>User #{index}</div> )}</FixedSizeList>→ DOM has ~20 nodes, not 10,000
→ 60 FPS smooth scroll
Never guess. Use React DevTools Profiler.
Look for:
Golden rule: Measure → Optimize → Measure again
// 1. Memoizing everythingconst Button = React.memo(({ onClick }) => <button onClick={onClick}>Click</button>);// 2. Inline objects in JSXreturn <Child config={{ theme: 'dark' }} />; // New object every render!// 3. No Suspense fallback<React.lazy(...) /> {/* Crash on slow network */}// 1. Memoize expensive components onlyconst Chart = React.memo(ExpensiveChart);// 2. Lift config outsideconst darkTheme = { theme: 'dark' };return <Child config={darkTheme} />;// 3. Always use Suspense<Suspense fallback={<Loading />}> <LazyDashboard /></Suspense>React.memo only on expensive components?useMemo/useCallback justified by cost?Performance isn't about making everything fast.
It's about making the right things fast.
Measure.
Target.
Optimize.
Your users don't care about useMemo.
They care about snappy UIs, fast loads, and smooth scrolling.
Master these tools — and build React apps that feel like native.
Written by James Miller
#React #Performance #Optimization #Frontend #WebDev #ReactProfiler #CodeSplitting