Irbisa · Шпаргалка
Производительность
React.memo, useMemo и useCallback, React Compiler, разбиение кода и lazy, виртуализация списков, Profiler, Core Web Vitals, размер бандла
Какими основными способами можно ускорить React-приложение и в каком порядке их применять?
Что делает
React.memoи когда мемоизированный компонент всё равно ререндерится?interface RowProps { label: string; onSelect: (label: string) => void;} const Row = memo(function Row({ label, onSelect }: RowProps) {…Найдите баг:
Chartобёрнут вmemo, но Profiler показывает, что он ререндерится на каждое нажатие клавиши в поиске.const Chart = memo(function Chart({ options, onPointClick }: ChartProps) { return <canvas data-type={options.type} onClick={() => onPointClick(0)} />;}); function Dashboard({ data }: { data: number[] }) { const [query, setQuery] = useState(''); return ( <> <input value={query} onChange={(e) => setQuery(e.target.value)} /> <Chart options={{ type: 'line', data }} onPointClick={(i) => console.log(data[i])} /> </> );}Чего стоит мемоизация и когда
React.memo,useMemoилиuseCallbackделают только хуже?Как избавиться от лишних ререндеров без мемоизации: опустить стейт ниже или передать компоненты через
children?// before: every scroll event re-renders ExpensiveTreefunction SlowPage() { const [scrollY, setScrollY] = useState(0); return ( <div onScroll={(e) => setScrollY(e.currentTarget.scrollTop)}> <Header shadow={scrollY > 0} />…Что такое React Compiler и делает ли он ненужными
useMemo,useCallbackиReact.memo?Как с помощью React DevTools Profiler узнать, какие компоненты ререндерятся и почему?
function onRender( id: string, phase: 'mount' | 'update' | 'nested-update', actualDuration: number, baseDuration: number,) {…Что такое code splitting и как
React.lazyиSuspenseзагружают компонент по требованию?const SettingsPage = lazy(() => import('./SettingsPage'));const preloadSettings = () => import('./SettingsPage'); export function App() { const [open, setOpen] = useState(false); return (…Найдите баг: ленивый редактор показывает fallback и теряет весь введённый текст при каждом ререндере родителя.
function NotePage({ noteId }: { noteId: string }) { const [saved, setSaved] = useState(false); const Editor = lazy(() => import('./Editor')); return ( <Suspense fallback={<p>Loading editor...</p>}> <Editor noteId={noteId} onSave={() => setSaved(true)} /> {saved && <p>Saved</p>} </Suspense> );}Найдите баг: график подгружается через
lazy, но вся библиотека графиков всё равно лежит в основном бандле.// Dashboard.tsximport { lazy, Suspense, useState } from 'react';import { CHART_COLORS } from './RevenueChart'; const RevenueChart = lazy(() => import('./RevenueChart')); export function Dashboard() { const [show, setShow] = useState(false); return ( <div style={{ borderColor: CHART_COLORS.primary }}> <button onClick={() => setShow(true)}>Show revenue</button> {show && ( <Suspense fallback={<p>Loading chart...</p>}> <RevenueChart /> </Suspense> )} </div> );}Что такое виртуализация списка (windowing), когда она нужна и как работает?
function LogList({ lines }: { lines: string[] }) { const parentRef = useRef<HTMLDivElement>(null); const virtualizer = useVirtualizer({ count: lines.length, getScrollElement: () => parentRef.current, estimateSize: () => 24,…Что такое Core Web Vitals (LCP, INP, CLS) и что в React-приложении обычно ухудшает каждую из метрик?
Что делают
<link rel="preload">,prefetchиpreconnect, и как их используют APIpreloadиpreinitиз React 19?import { preconnect, prefetchDNS, preinit, preload } from 'react-dom';import { Link } from 'react-router'; export function CheckoutPage() { // called during render: with SSR they go out in the HTML before the form needs them preconnect('https://api.payments.example');…Как загружать веб-шрифты без невидимого текста и сдвигов вёрстки?
/* in <head>, for the one file used above the fold: <link rel="preload" href="/fonts/inter-latin.woff2" as="font" type="font/woff2" crossorigin> */ @font-face { font-family: 'Inter'; src: url('/fonts/inter-latin.woff2') format('woff2');…Когда в React-приложении стоит переносить работу в Web Worker, и как с ним общаться?
// sort.worker.ts: runs on its own thread, no DOM and no Reactself.onmessage = (e: MessageEvent<Row[]>) => { const sorted = [...e.data].sort(compareRows); // the 300 ms part self.postMessage(sorted);};…Почему клик или ввод в React-приложении ощущается медленным (плохой INP) и как разбить долгую работу рендера?
function ReportPage({ rows }: { rows: Row[] }) { const [tab, setTab] = useState<'summary' | 'details'>('summary'); const [isPending, startTransition] = useTransition(); function selectTab(next: 'summary' | 'details') { // the heavy tab renders in interruptible slices…Что делает компонент
<Activity>, появившийся в React 19.2, и как он ускоряет навигацию?function Tabs({ tab }: { tab: 'feed' | 'profile' }) { return ( <> <Activity mode={tab === 'feed' ? 'visible' : 'hidden'}> <Feed /> </Activity>…Как измерять производительность React-приложения в продакшене, а не на своей машине?
import { onCLS, onINP, onLCP, type Metric } from 'web-vitals'; function send(metric: Metric) { const body = JSON.stringify({ name: metric.name, value: metric.value,…Как понять, из-за чего React-бандл получился большим, и как его уменьшить?
Таблица на 5000 строк зависает при каждом нажатии клавиши в поле фильтра. Расскажите, как вы будете искать причину и исправлять.