Реальна різниця між useMemo та React.memo в React
У світі React оптимізація продуктивності компонентів є однією з найважливіших задач. Два популярні інструменти для цього — це хук useMemo
і вищий орієнтований компонент React.memo
. Вони часто викликають плутанину, адже обидва працюють з продуктивністю, але мають зовсім різні сфери застосування. У цій статті розглянемо, чим саме відрізняються useMemo
та React.memo
, коли їх варто використовувати і як уникнути поширених помилок.
Що таке useMemo
?
Основна ідея
useMemo
— це хук, який використовується для мемоізації значень. Він обчислює значення та кешує його, доки залишається незмінною залежність. Це корисно, коли у вас є дорогі обчислення, які не потрібно виконувати при кожному рендері компонента.
Синтаксис
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Як працює
- Функція, передана в
useMemo
, виконується лише тоді, коли змінюються залежності (у цьому випадкуa
абоb
). - Якщо залежності не змінюються,
useMemo
повертає кешоване значення.
Приклад використання
import React, { useState, useMemo } from 'react';
function ExpensiveComponent({ items }) {
const expensiveCalculation = (arr) => {
console.log('Виконуємо обчислення...');
return arr.reduce((sum, item) => sum + item, 0);
};
const [count, setCount] = useState(0);
const total = useMemo(() => expensiveCalculation(items), [items]);
return (
<div>
<h1>Сума: {total}</h1>
<button onClick={() => setCount(count + 1)}>Клікнуто {count} разів</button>
</div>
);
}
Результат: Обчислення виконується лише тоді, коли змінюється масив items
. Клік на кнопку не викликає повторних обчислень.
Що таке React.memo
?
Основна ідея
React.memo
— це вищий орієнтований компонент (HOC), який запобігає зайвим рендерам компонента, якщо його пропси не змінилися. Він працює шляхом порівняння старих і нових пропсів.
Синтаксис
const MemoizedComponent = React.memo(MyComponent);
Як працює
React.memo
автоматично використовує поверхневе порівняння пропсів.- Якщо пропси не змінюються, компонент не перерендерюється.
Приклад використання
import React from 'react';
const MyComponent = ({ value }) => {
console.log('Рендеримо компонент');
return <div>{value}</div>;
};
const MemoizedComponent = React.memo(MyComponent);
function App() {
return (
<div>
<MemoizedComponent value="React.memo" />
</div>
);
}
Результат: Компонент MyComponent
не буде перерендерюватися, якщо проп value
не змінюється.
Головні відмінності між useMemo
та React.memo
Характеристика | useMemo |
React.memo |
---|---|---|
Призначення | Мемоізує значення (обчислення, функції). | Запобігає зайвим рендерам компонента. |
Де використовується | У функціональних компонентах. | У функціональних компонентах або їх експорті. |
Що оптимізує | Обчислення, які залежать від залежностей. | Рендеринг компонентів із незмінними пропсами. |
Сфера застосування | Для важких обчислень або великих даних. | Для оптимізації роботи дочірніх компонентів. |
API | Хук (використовується всередині компонентів). | Вищий орієнтований компонент (HOC). |
Коли використовувати useMemo
?
- Важкі обчислення
Якщо у вас є обчислення, яке займає багато часу, і результат залежить лише від певних параметрів, використовуйтеuseMemo
.Приклад: Підрахунок суми чисел, фільтрація чи сортування великих масивів.
- Мемоізація функцій
Хоча для функцій краще підходитьuseCallback
,useMemo
також може використовуватися для мемоізації функцій.Приклад:
const memoizedFunction = useMemo(() => () => console.log('Hello'), []);
Коли використовувати React.memo
?
- Дочірні компоненти
Якщо компонент отримує пропси, які змінюються рідко, варто використовуватиReact.memo
. - Списки та їхні елементи
Для великих списків можна мемоізувати кожен елемент за допомогоюReact.memo
, щоб уникнути рендерингу незмінних елементів.Приклад:
const ListItem = React.memo(({ item }) => { console.log('Рендеримо елемент', item); return <li>{item}</li>; });
- Кастомне порівняння пропсів
Якщо потрібно порівнювати пропси вручну, можна передати функціюareEqual
як другий аргумент:const MemoizedComponent = React.memo(MyComponent, (prevProps, nextProps) => { return prevProps.value === nextProps.value; });
Поширені помилки
- Надмірне використання
ВикористанняuseMemo
абоReact.memo
там, де це не потрібно, може ускладнити код без значного виграшу в продуктивності. - Ігнорування залежностей
Неправильне вказування або пропуск залежностей уuseMemo
може призвести до непередбачуваної поведінки.Приклад помилки:
const result = useMemo(() => computeValue(a, b), []); // Неправильно: залежності відсутні
- Неочікувана зміна пропсів
Якщо пропси є об’єктами чи функціями, вони можуть змінюватися через зміну посилань. ВикористовуйтеuseCallback
абоuseMemo
для стабілізації.
Поєднання useMemo
та React.memo
Ці інструменти часто використовуються разом для забезпечення оптимальної продуктивності:
const ChildComponent = React.memo(({ value }) => {
console.log('Рендеримо компонент');
return <div>{value}</div>;
});
function ParentComponent() {
const [count, setCount] = useState(0);
const memoizedValue = useMemo(() => `Value: ${count}`, [count]);
return (
<div>
<ChildComponent value={memoizedValue} />
<button onClick={() => setCount(count + 1)}>Збільшити</button>
</div>
);
}
Висновок
- Використовуйте
useMemo
для мемоізації значень та важких обчислень, які залежать від змінних. - Використовуйте
React.memo
для запобігання зайвим рендерам компонентів із незмінними пропсами. - Завжди пам’ятайте, що надмірна оптимізація може зробити код складнішим без значного приросту продуктивності. Застосовуйте ці інструменти лише там, де це справді необхідно.
Дотримуючись цих принципів, ви зможете створювати продуктивніші та масштабованіші React-додатки! 🚀