Performance
1 min readRapid overview
React Performance Optimization
React.memo
// Prevents re-render if props haven't changed
const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
return <div>{/* expensive rendering */}</div>;
});
// Custom comparison
const MemoizedComponent = React.memo(
Component,
(prevProps, nextProps) => {
return prevProps.id === nextProps.id; // true = skip render
}
);
Code Splitting
import { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
);
}
Virtual Lists
import { FixedSizeList } from 'react-window';
function VirtualList({ items }) {
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index]}</div>
)}
</FixedSizeList>
);
}
Profiler API
import { Profiler } from 'react';
function onRenderCallback(
id, // component id
phase, // "mount" or "update"
actualDuration, // time spent rendering
baseDuration, // estimated time without memoization
startTime,
commitTime,
interactions
) {
console.log(`${id} took ${actualDuration}ms to ${phase}`);
}
function App() {
return (
<Profiler id="App" onRender={onRenderCallback}>
<Router />
</Profiler>
);
}
Optimization Patterns
// ✅ Avoid inline object/array creation in render
function Parent() {
const config = useMemo(() => ({ theme: 'dark' }), []);
return <Child config={config} />;
}
// ✅ Debounce expensive operations
const debouncedSearch = useMemo(
() => debounce((query) => search(query), 300),
[]
);
// ✅ Lazy initialize state
const [data, setData] = useState(() => expensiveComputation());
// ✅ Batch state updates
ReactDOM.unstable_batchedUpdates(() => {
setState1(value1);
setState2(value2);
});