useMemo и useCallback для производительности
Мемоизируйте ресурсоёмкие вычисления с помощью useMemo, а стабильные ссылки на функции — с помощью useCallback, чтобы предотвращать ненужный повторный рендер дочерних компонентов.
«useMemo и useCallback для производительности» — бесплатный урок Frontend Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Frontend Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Frontend Academy содержит 4 уроков всего.
Поведение React по умолчанию
По умолчанию React выполняет повторный рендеринг компонента при каждом изменении его состояния или повторном рендеринге родителя. Дочерние компоненты также выполняют повторный рендеринг, даже если их пропсы не изменились. Для большинства компонентов это нормально — React работает быстро.
useMemo — мемоизация ресурсоёмких значений
useMemo(fn, deps) кэширует результат вычисления. Функция выполняется только при изменении зависимостей. Используйте его для ресурсоёмких вычислений, повторение которых при каждом рендеринге было бы расточительным.
const expensiveResult = useMemo(() => {
return items.filter(item => item.category === category).sort((a, b) => a.price - b.price);
}, [items, category]);
// Only recalculates when items or category changesuseCallback — мемоизация функций
useCallback(fn, deps) возвращает мемоизированную функцию, которая сохраняет ту же ссылку, пока не изменятся зависимости. Используйте его при передаче функций обратного вызова глубоко вложенным или мемоизированным компонентам.
const handleDelete = useCallback((id: string) => {
setItems(prev => prev.filter(item => item.id !== id));
}, []); // stable reference — empty deps because only setItems is used
<ItemList items={items} onDelete={handleDelete} />React.memo — пропуск повторного рендеринга
React.memo(Component) оборачивает компонент так, чтобы он выполнял повторный рендеринг только при изменении его пропсов (поверхностное сравнение). Объединяйте его с useCallback для стабильных пропсов-функций обратного вызова.
const MemoItem = React.memo(function Item({ text, onDelete }: ItemProps) {
console.log('Item rendered:', text); // only logs when props change
return <li>{text} <button onClick={onDelete}>×</button></li>;
});
// onDelete must be stable (from useCallback) for memo to helpКогда НЕ следует оптимизировать
Преждевременная оптимизация — это ловушка. У useMemo и useCallback есть своя стоимость: замыкание и сравнение зависимостей. Для дешёвых операций (например, фильтрации 10 элементов) накладные расходы превышают пользу. Оптимизируйте, только измерив реальную проблему с производительностью.
Профилирование перед оптимизацией
Используйте профилировщик React DevTools, чтобы измерить фактическое время рендеринга до добавления мемоизации. Профилировщик показывает, какие компоненты работают дольше всего и сколько раз они выполняют рендеринг. Исправляйте проблемы на основе фактов, а не предположений.
useMemo для стабильных ссылок
useMemo также полезен для сохранения стабильной ссылки — не ради производительности самого вычисления, а чтобы предотвратить ненужный повторный запуск последующей мемоизации или эффекта.
// Without useMemo, this creates a new array every render:
const config = useMemo(() => ({ endpoint: '/api', timeout: 5000 }), []);
// Without memoization, useEffect would re-run on every render:
useEffect(() => { initSDK(config); }, [config]);Зависимости useCallback
Для useCallback действуют те же правила зависимостей, что и для useEffect. Включайте каждую переменную из внешней области видимости, которую использует функция обратного вызова. Установщики состояния (из useState) всегда стабильны, поэтому добавлять их в зависимости не нужно.
Связь между useMemo и useCallback
useCallback(fn, deps) эквивалентен useMemo(() => fn, deps). Механизм один и тот же — useCallback всего лишь удобная запись для мемоизации именно функций.
Мемоизация элементов списка
Распространённый шаблон: мемоизируйте компоненты элементов списка, когда список большой и часто выполняет повторный рендеринг. Передавайте стабильные функции обратного вызова из useCallback, чтобы не свести мемоизацию на нет.
const MemoRow = React.memo(Row);
const handleEdit = useCallback((id) => edit(id), []);
const handleDel = useCallback((id) => remove(id), []);
{rows.map(row => (
<MemoRow key={row.id} row={row} onEdit={handleEdit} onDelete={handleDel} />
))}Мемоизация значения контекста
Мемоизируйте значение, передаваемое Provider контекста, чтобы все потребители не выполняли повторный рендеринг при каждом повторном рендеринге родителя Provider.
const value = useMemo(() => ({ user, login, logout }), [user]);Быстрая проверка
Каково назначение useCallback?
Краткое повторение: useMemo и useCallback
useMemo кэширует дорогостоящие вычисленные значения. useCallback кэширует ссылки на функции. React.memo пропускает повторный рендеринг, если пропсы не изменились при поверхностном сравнении. Объединяйте все три средства для повышения производительности компонента. Сначала профилируйте — преждевременная мемоизация усложняет код без пользы. Стабильные ссылки предотвращают повторный запуск последующих эффектов и мемоизации.
Часто задаваемые вопросы
Урок «useMemo и useCallback для производительности» бесплатный?
Да — полный текст урока «useMemo и useCallback для производительности» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Frontend Academy, подпишись на CoddyKit PRO. Курс Frontend Academy содержит 4 уроков всего.
Чему я научусь в уроке «useMemo и useCallback для производительности»?
Мемоизируйте ресурсоёмкие вычисления с помощью useMemo, а стабильные ссылки на функции — с помощью useCallback, чтобы предотвращать ненужный повторный рендер дочерних компонентов. Ты практикуешь Frontend Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Frontend Academy?
Предыдущий опыт не требуется. Frontend Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «useMemo и useCallback для производительности»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Frontend Academy?
Да. Каждый урок Frontend Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- useContext для глобального состояния
- useReducer для сложного состояния
- useMemo и useCallback для производительности
- Пользовательские хуки: выделение повторно используемой логики