Оптимизация производительности
Каким образом можно оптимизировать производительность React-приложения?
Оптимизация производительности React-приложения:
-
Использование
React.memo:- Предотвращает ненужные повторные рендеры компонентов, если их пропсы не изменились.
const MyComponent = React.memo(function MyComponent(props) { // компонент }); -
Использование хуков
useMemoиuseCallback:- Мемоизация значений и функций, чтобы избежать их пересоздания при каждом рендере.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]); -
Виртуализация списков:
- Рендеринг только видимых элементов списка с помощью библиотек, таких как
react-window.
import { FixedSizeList as List } from 'react-window'; - Рендеринг только видимых элементов списка с помощью библиотек, таких как
-
Разделение кода (Code Splitting):
- Динамическая загрузка компонентов с помощью
React.lazyиReact.Suspense.
const MyComponent = React.lazy(() => import('./MyComponent')); - Динамическая загрузка компонентов с помощью
-
Контроль обновлений с помощью
shouldComponentUpdateилиPureComponent:- В классовых компонентах использовать
shouldComponentUpdateили наследовать отReact.PureComponent.
class MyComponent extends React.PureComponent { // компонент } - В классовых компонентах использовать
-
Оптимизация изображений:
- Использование форматов изображений сжатого размера и отложенная загрузка (lazy loading).
Оптимизация производительности React-приложения достигается с помощью мемоизации, виртуализации списков, разделения кода и контроля обновлений компонентов, что снижает нагрузку на рендеринг и улучшает скорость работы приложения.
Как использовать memoization для оптимизации компонентов?
Мемоизация — это техника, которая позволяет оптимизировать производительность компонентов, избегая повторных вычислений и рендеров, если входные данные не изменились.
Основные хуки для мемоизации:
-
useMemo:- Мемоизирует вычисленное значение.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); -
useCallback:- Сохраняет ссылку на функцию между рендерами, пока зависимости не изменились. Передаваемое выражение функции всё равно вычисляется при рендере, но useCallback может вернуть ранее сохранённую функцию.
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
Пример использования:
import React, { useMemo, useCallback } from "react";
const MyComponent = ({ a, b }) => {
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
return (
<div>
<div>{memoizedValue}</div>
<button onClick={memoizedCallback}>Click me</button>
</div>
);
};
export default MyComponent;
Мемоизация с помощью useMemo и useCallback позволяет оптимизировать производительность компонентов, предотвращая ненужные вычисления и рендеры при неизменных входных данных.
Что такое “глубокое сравнение” (deep comparison) в контексте оптимизации производительности React?
Глубокое сравнение — это процесс рекурсивной проверки всех уровней вложенности объектов или массивов для определения их эквивалентности.
В контексте React:
-
React сравнивает зависимости useEffect, useMemo и useCallback через Object.is, без глубокого обхода. Глубокое сравнение нужно реализовать явно, например в пользовательской функции сравнения memo, и сначала измерить его стоимость.
-
Цель: Оптимизация производительности путем предотвращения ненужных рендеров, когда значения не изменились на глубоком уровне.
Пример:
Антипример: добавление isEqual в зависимости не включает глубокое сравнение. Код ниже по-прежнему сравнивает data по Object.is и вообще не вызывает isEqual.
import { useEffect } from "react";
import isEqual from "lodash.isequal";
const MyComponent = ({ data }) => {
useEffect(() => {
// Действия при изменении data
}, [data, isEqual]);
return <div>{/* компонент */}</div>;
};
Глубокое сравнение может стоить дороже повторного рендера. Обычно сначала сохраняют стабильные ссылки и упрощают зависимости; специальный компаратор применяют только после измерения и с учётом всех значимых полей, включая функции.