React: Performance

Здесь — React-специфичная оптимизация. Общую диагностику производительности (main thread, Web Vitals, layout thrashing) см. в Производительность рендеринга.

Какие методы оптимизации вы используете?

1. Мемоизация:

// React.memo — пропускает ре-рендер если пропсы не изменились
const List = React.memo(({ items }) => (
  <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>
));
 
// useMemo — мемоизирует тяжёлые вычисления
const sorted = useMemo(() => [...items].sort(compareFn), [items]);
 
// useCallback — стабильная ссылка на функцию
const handleClick = useCallback((id) => deleteItem(id), []);

2. Code Splitting — разбиение бандла на чанки:

// React.lazy + Suspense — загружает компонент только при обращении
const HeavyChart = React.lazy(() => import('./HeavyChart'));
 
function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyChart />
    </Suspense>
  );
}

3. Ленивая загрузка роутов:

// React Router v6 — каждый роут загружается отдельным чанком
const Home    = lazy(() => import('./pages/Home'));
const Profile = lazy(() => import('./pages/Profile'));
 
<Routes>
  <Route path="/"        element={<Suspense fallback={<Loader />}><Home /></Suspense>} />
  <Route path="/profile" element={<Suspense fallback={<Loader />}><Profile /></Suspense>} />
</Routes>

4. Избегать инлайновых объектов и функций в пропсах:

// ❌ Новая ссылка при каждом рендере → React.memo бесполезен
<Button onClick={() => doSomething()} style={{ color: 'red' }} />
 
// ✅ Стабильные ссылки
const handleClick = useCallback(() => doSomething(), []);
const style = useMemo(() => ({ color: 'red' }), []);
<Button onClick={handleClick} style={style} />

Разбиение vendor-кода на уровне сборки (splitChunks) — см. webpack.


Профилирование ре-рендеров

Без профилировщиков — базовые практики:

  1. React.memo для мемоизации компонентов.
  2. useMemo / useCallback для значений и функций.
  3. React.lazy + Suspense для разделения кода.
  4. Избегать инлайновых функций/объектов в пропсах.

С профилировщиками:

React DevTools Profiler
  → Flame graph — показывает время рендера каждого компонента
  → Ranked chart — компоненты по убыванию времени рендера

why-did-you-render (пакет)
  → Логирует причины ре-рендеров в консоль
// Подключение why-did-you-render
import React from 'react';
import whyDidYouRender from '@welldone-software/why-did-you-render';
 
if (process.env.NODE_ENV === 'development') {
  whyDidYouRender(React, { trackAllPureComponents: true });
}

См. также

  • rendering-performance — общая производительность и Web Vitals
  • hooks — useMemo/useCallback
  • webpack — splitChunks, разделение бандла