Що робить useMemo()?
Що робить useMemo()
Хук useMemo() - це мемоізація обчисленого значення.
Він запам'ятовує результат виконання функції між рендерами
і повторно обчислює його тільки тоді, коли змінюються залежності.
Синтаксис
const memoizedValue = useMemo(() => computeSomething(a, b), [a, b]);- Перший аргумент - функція, яка повертає результат (обчислення, фільтрація, сортування тощо).
- Другий - масив залежностей
[a, b].
React запам'ятає результат і при наступному рендері:
- якщо залежності не змінилися -> поверне старе значення;
- якщо залежності змінилися -> перерахує заново.
Приклад без useMemo
function App({ list }) {
const sorted = list.sort(); // кожен рендер - сортування
return <List items={sorted} />;
}Кожен рендер буде викликати list.sort(),
і навіть якщо list не змінилася - створюється новий масив.
Якщо <List /> мемоізований через React.memo,
він все одно буде ререндеритися,
тому що sorted -> нове посилання (новий об'єкт у пам'яті).
З useMemo
function App({ list }) {
const sorted = useMemo(() => [...list].sort(), [list]);
return <List items={sorted} />;
}Тепер:
- Поки
listне змінилася, React поверне старе посилання наsorted; List(якщо вінReact.memo) не буде ререндеритися;- Це запобігає зайвим ререндерам і зайвим обчисленням.
Приклад з обчисленням
function ExpensiveComponent({ value }) {
const heavyResult = useMemo(() => {
console.log('expensive calculation');
return fibonacci(value); // припустимо, дорога функція
}, [value]);
return <div>Result: {heavyResult}</div>;
}Без useMemo:
- При кожному рендері викликається
fibonacci(value), навіть якщоvalueне змінювалася.
З useMemo:
- Обчислення відбудеться тільки один раз,
поки
valueзалишається тим самим -> React поверне закешований результат.
Як useMemo допомагає уникнути зайвих ререндерів
Сценарій: "мемоізована дитина"
const Child = React.memo(({ data }) => {
console.log('Child render');
return <div>{data.length}</div>;
});
function Parent({ items }) {
const processed = useMemo(() => items.filter(i => i.active), [items]);
return <Child data={processed} />;
}Якщо items не змінилися,
-> processed залишається тим самим посиланням
-> React.memo розуміє, що проп data не змінився
-> Child не ререндериться.
Без useMemo processed створювався б заново,
і Child щоразу перемальовувався б,
навіть при незмінних даних.
Що кешує useMemo
| Тип значення | Кешується? | Приклад |
|---|---|---|
| Примітиви | Так | number, string, boolean |
| Об'єкти та масиви | Так | const arr = useMemo(() => [...list], [list]) |
| Результат функції | Так | useMemo(() => compute(), [deps]) |
| Сама функція | Ні -> для цього useCallback() |
useCallback(fn, deps)- це просто скорочення дляuseMemo(() => fn, deps).
Коли варто використовувати useMemo
Використовуй, якщо:
- Є дороге обчислення (фільтрація, сортування, підрахунки);
- Потрібно зберегти посилання на об'єкт/масив між рендерами (для
React.memo); - Компонент часто ререндериться, а залежні дані - рідко змінюються.
Коли не потрібно використовувати
Не застосовуй скрізь підряд:
- Якщо обчислення дешеве (кілька операцій) -
useMemoтільки сповільнить (React все одно порівняє deps, створить кеш); - Якщо компонент все одно ререндериться повністю (і
useMemoне бере участі в props інших компонентів); - Якщо дані і так стабільні за посиланням (наприклад, ти не створюєш новий об'єкт щоразу).
Підсумок: useMemo vs useCallback
| Хук | Що робить | Повертає | Типова мета |
|---|---|---|---|
useMemo(fn, deps) | Кешує результат обчислення | Значення | Зберегти результат між рендерами |
useCallback(fn, deps) | Кешує функцію | Функцію | Зберегти посилання на обробник |
Коротко і по суті
| Що робить | Як допомагає |
|---|---|
| Кешує результат обчислень | Уникає повторних важких операцій |
| Зберігає посилання на об'єкт/масив | Допомагає React.memo побачити, що prop не змінився |
| Працює тільки при незмінних залежностях | React повертає старе значення |
| Знижує кількість ререндерів | Дочірні компоненти не перемальовуються |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.