Optimize React applications for better user experience.
React.memo for Component Memoization#
1const ExpensiveList = React.memo(function ExpensiveList({ items }: Props) {
2 return (
3 <ul>
4 {items.map(item => (
5 <li key={item.id}>{item.name}</li>
6 ))}
7 </ul>
8 );
9});
10
11// Custom comparison
12const UserCard = React.memo(
13 ({ user }: { user: User }) => <div>{user.name}</div>,
14 (prev, next) => prev.user.id === next.user.id
15);useMemo and useCallback#
1function SearchResults({ query, items }: Props) {
2 const filteredItems = useMemo(() => {
3 return items.filter(item =>
4 item.name.toLowerCase().includes(query.toLowerCase())
5 );
6 }, [items, query]);
7
8 const handleSelect = useCallback((id: string) => {
9 setSelected(id);
10 }, []);
11
12 return <List items={filteredItems} onSelect={handleSelect} />;
13}Code Splitting#
1import { lazy, Suspense } from 'react';
2
3const HeavyChart = lazy(() => import('./HeavyChart'));
4
5function App() {
6 return (
7 <Suspense fallback={<Loading />}>
8 <HeavyChart />
9 </Suspense>
10 );
11}Virtualization#
1import { useVirtualizer } from '@tanstack/react-virtual';
2
3function VirtualList({ items }: { items: Item[] }) {
4 const parentRef = useRef<HTMLDivElement>(null);
5
6 const virtualizer = useVirtualizer({
7 count: items.length,
8 getScrollElement: () => parentRef.current,
9 estimateSize: () => 50,
10 });
11
12 return (
13 <div ref={parentRef} style={{ height: 400, overflow: 'auto' }}>
14 <div style={{ height: virtualizer.getTotalSize() }}>
15 {virtualizer.getVirtualItems().map(virtualItem => (
16 <div
17 key={virtualItem.key}
18 style={{
19 position: 'absolute',
20 transform: `translateY(${virtualItem.start}px)`,
21 }}
22 >
23 {items[virtualItem.index].name}
24 </div>
25 ))}
26 </div>
27 </div>
28 );
29}Deferred Values and Transitions#
1import { useDeferredValue, useTransition } from 'react';
2
3function Search() {
4 const [query, setQuery] = useState('');
5 const deferredQuery = useDeferredValue(query);
6
7 const [isPending, startTransition] = useTransition();
8
9 const handleChange = (e) => {
10 setQuery(e.target.value);
11 startTransition(() => {
12 setResults(filter(e.target.value));
13 });
14 };
15}Profile first, optimize bottlenecks, and measure improvements.