Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
Performance optimization is about making smart decisions based on measurements, not assumptions. Always profile before optimizing, and focus on the bottlenecks that actually impact user experience.
Use React DevTools Profiler to identify actual bottlenecks.
Optimize the 20% that causes 80% of performance issues.
Clean, simple code is often faster than over-optimized code.
Wrap components in React.memo to skip re-rendering when props haven't changed.
💡 Use when: Component renders often with same props, or renders are expensive
Cache computed values so they're not recalculated on every render.
💡 Use when: Calculation is expensive (filtering/sorting large arrays, complex math)
Prevent creating new function instances on every render.
💡 Use when: Passing callbacks to memoized child components
Load components only when needed
import React, { lazy, Suspense } from 'react';
// Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'));
const AdminPanel = lazy(() => import('./AdminPanel'));
function Dashboard() {
const [showChart, setShowChart] = React.useState(false);
return (
<div>
<h1>Dashboard</h1>
<button onClick={() => setShowChart(true)}>
Show Chart
</button>
{showChart && (
<Suspense fallback={<div>Loading chart...</div>}>
<HeavyChart />
</Suspense>
)}
</div>
);
}
// Route-based code splitting
import { lazy } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}Render only visible items in large lists
import { FixedSizeList } from 'react-window';
// ❌ BAD: Renders all 10,000 items
function SlowList({ items }) {
return (
<div>
{items.map(item => (
<div key={item.id} style={{ height: 50 }}>
{item.name}
</div>
))}
</div>
);
}
// ✅ GOOD: Only renders visible items
function FastList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>
{items[index].name}
</div>
);
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{Row}
</FixedSizeList>
);
}
// Key prop optimization
// ❌ BAD: Using array index
items.map((item, index) => <Item key={index} {...item} />)
// ✅ GOOD: Using stable ID
items.map(item => <Item key={item.id} {...item} />)
// Pagination for very large datasets
function PaginatedList({ items, pageSize = 20 }) {
const [page, setPage] = React.useState(0);
const visibleItems = React.useMemo(() => {
const start = page * pageSize;
return items.slice(start, start + pageSize);
}, [items, page, pageSize]);
return (
<div>
{visibleItems.map(item => (
<Item key={item.id} {...item} />
))}
<button onClick={() => setPage(p => p + 1)}>
Next Page
</button>
</div>
);
}Keep state close to where it's used
// ❌ BAD: State too high up causes unnecessary re-renders
function App() {
const [theme, setTheme] = useState('light');
const [userName, setUserName] = useState('');
const [searchQuery, setSearchQuery] = useState('');
return (
<div>
<Header theme={theme} /> {/* Re-renders on ANY state change */}
<SearchBox query={searchQuery} onChange={setSearchQuery} />
<UserProfile name={userName} onChange={setUserName} />
<Footer theme={theme} />
</div>
);
}
// ✅ GOOD: State collocated with usage
function App() {
const [theme, setTheme] = useState('light');
return (
<div>
<Header theme={theme} />
<SearchBox /> {/* Manages own state */}
<UserProfile /> {/* Manages own state */}
<Footer theme={theme} />
</div>
);
}
function SearchBox() {
const [query, setQuery] = useState(''); // Local state
return <input value={query} onChange={e => setQuery(e.target.value)} />;
}
// Context optimization with split providers
// ❌ BAD: Single context causes all consumers to re-render
const AppContext = createContext();
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState('light');
const [settings, setSettings] = useState({});
return (
<AppContext.Provider value={{ user, theme, settings, setUser, setTheme, setSettings }}>
{children}
</AppContext.Provider>
);
}
// ✅ GOOD: Split contexts by concern
const UserContext = createContext();
const ThemeContext = createContext();
const SettingsContext = createContext();
// Only components using theme re-render when theme changes!New object/array references cause unnecessary re-renders.
New function instances break memoization.
Context updates re-render ALL consumers, even if they don't use changed values.
Missing or unstable keys cause React to recreate DOM nodes unnecessarily.
Identify which components are slow and re-rendering frequently
Use React.memo, useMemo, and useCallback where measurements show benefit
Use React.lazy for routes and heavy components
Implement virtualization for lists with 100+ items
Compress images, use modern formats, lazy load below fold
Tree-shake, analyze bundle, replace heavy dependencies
Profile after changes to verify improvements
Always profile before optimizing. Don't guess where bottlenecks are!
Prevent unnecessary re-renders of expensive components.
Use React.lazy to reduce initial bundle size significantly.
Keep state close to where it's used to minimize re-renders.
Compress images, use modern formats, lazy load below fold.
Don't over-optimize. Clean code is often fast enough!