Как работает UseMemo?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает useMemo?
useMemo — это React хук, который кэширует и мемоизирует результат дорогостоящего вычисления и возвращает его только если зависимости изменились. Это оптимизационный хук, который помогает избежать ненужных пересчётов в компонентах и значительно улучшает производительность приложения.
Синтаксис и базовое использование
const memoizedValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
Как работает:
- Первый рендер: computeExpensiveValue выполняется, результат сохраняется
- Второй рендер (a, b не изменились): возвращает сохранённый результат
- Третий рендер (a изменился): выполняется вычисление заново
Пример: дорогостоящее вычисление
import { useMemo, useState } from "react";
function OptimizedComponent() {
const [count, setCount] = useState(0);
const expensiveResult = useMemo(() => {
return Array(1000000)
.fill(0)
.reduce((sum, _, i) => sum + i, 0);
}, []);
return (
<div>
<p>Результат: {expensiveResult}</p>
<button onClick={() => setCount(count + 1)}>
Клик: {count}
</button>
</div>
);
}
Практический пример: фильтрация списка
function UserList({ users, searchQuery }) {
const filteredUsers = useMemo(() => {
return users.filter(user =>
user.name.toLowerCase().includes(searchQuery.toLowerCase())
);
}, [users, searchQuery]);
return (
<ul>
{filteredUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Работа с зависимостями
Пустой массив — один раз вычисляет при монтировании:
const value = useMemo(() => {
return expensiveComputation();
}, []);
Массив с зависимостями — вычисляет при изменении:
const value = useMemo(() => {
return computeResult(count, name);
}, [count, name]);
Сравнение с useCallback
- useMemo кэширует ЗНАЧЕНИЕ (результат вычисления)
- useCallback кэширует ФУНКЦИЮ
const memoizedValue = useMemo(() => ({ id: 1 }), []);
const memoizedFunc = useCallback(() => {}, []);
Оптимизация дочерних компонентов
function Parent() {
const userConfig = useMemo(() => ({
theme: "dark",
fontSize: 16
}), []);
return <Child config={userConfig} />;
}
const Child = React.memo(({ config }) => {
return <div>Theme: {config.theme}</div>;
});
Один и тот же объект — дочерний не перерендерится.
Реальный пример: обработка таблицы
function DataTable({ data, sortBy, filterQuery }) {
const processedData = useMemo(() => {
let result = [...data];
if (filterQuery) {
result = result.filter(item =>
item.name.toLowerCase().includes(filterQuery.toLowerCase())
);
}
if (sortBy) {
result.sort((a, b) => {
return a[sortBy] > b[sortBy] ? 1 : -1;
});
}
return result;
}, [data, sortBy, filterQuery]);
return (
<table>
<tbody>
{processedData.map(item => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
);
}
Когда использовать useMemo
ИСПОЛЬЗУЙ когда:
- Дорогостоящие вычисления (> 1ms)
- Результат передаётся в React.memo компонент
- Фильтрация/сортировка больших массивов
- Создание объектов для зависимостей дочерних компонентов
НЕ ИСПОЛЬЗУЙ когда:
- Простые вычисления (count * 2)
- Простые значения (строки, числа)
- Нет реальной необходимости в оптимизации
Частые ошибки
Ошибка: забыли добавить зависимость
const result = useMemo(() => {
return compute(count);
}, []); // count используется, но не в зависимостях!
Испраляю:
const result = useMemo(() => {
return compute(count);
}, [count]);
Ошибка: функция в зависимостях
const value = useMemo(() => {
return compute();
}, [() => {}]); // НОВАЯ функция каждый рендер!
Исправляю с useCallback:
const callback = useCallback(() => {}, []);
const value = useMemo(() => {
return compute();
}, [callback]);
Лучшие практики
- Всегда используй правильные зависимости — eslint поможет
- Не оптимизируй прежде, чем измеришь — используй React DevTools Profiler
- Не переусложняй — useMemo добавляет память и сложность
- Используй для реально дорогих операций — вычисления, большие преобразования
useMemo — мощный инструмент для оптимизации React приложений, но использовать его нужно осознанно. Преждевременная оптимизация — корень всех зол!