Що робить React.memo()?
Що робить React.memo()
React.memo() - це обгортка для функціонального компонента,
яка каже React:
«Якщо пропси не змінилися - не ререндер цей компонент повторно.»
Синтаксис
const MemoizedComponent = React.memo(MyComponent);або одразу:
export default React.memo(function MyComponent(props) {
return <div>{props.value}</div>;
});Як це працює
React при кожному рендері порівнює пропси нового і попереднього виклику компонента. Якщо пропси рівні за поверхневим порівнянням (shallow comparison):
- компонент не викликається повторно;
- повертається попереднє відрендерене дерево.
Приклад:
function Child({ value }) {
console.log('Child render');
return <div>{value}</div>;
}
const MemoChild = React.memo(Child);
function Parent() {
const [count, setCount] = useState(0);
console.log('Parent render');
return (
<>
<MemoChild value="static" />
<button onClick={() => setCount(c => c + 1)}>+</button>
</>
);
}Що відбудеться:
Parent render
Child render ← перший рендер
Parent render ← після кліку
(Child не ререндериться)React.memo помітив, що props.value не змінився → не став викликати компонент.
Якщо не вказати React.memo
Тоді щоразу, коли батько ререндериться, усі дочірні компоненти будуть викликатися заново - навіть якщо їхні пропси не змінилися.
function Child({ value }) {
console.log('Child render');
return <div>{value}</div>;
}
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<Child value="static" /> {/* буде ререндеритися завжди */}
<button onClick={() => setCount(c => c + 1)}>+</button>
</>
);
}Кожне натискання кнопки викликає:
Parent render
Child render (зайвий рендер)Як React.memo порівнює пропси
React робить поверхневе (shallow) порівняння:
- порівнює примітиви (
number,string,boolean) за значенням; - порівнює об'єкти/масиви/функції за посиланням.
Важливо
const data = { name: 'Tim' };
<MemoChild user={data} />Навіть якщо об'єкт виглядає однаково,
React побачить нове посилання на { name: 'Tim' } щорендеру,
і MemoChild все одно перемалюється.
Рішення - мемоізувати об'єкт:
const data = useMemo(() => ({ name: 'Tim' }), []);
<MemoChild user={data} />Кастомна функція порівняння
Можна передати другий аргумент - функцію, яка сама вирішує, чи потрібно ререндерити:
const MemoChild = React.memo(Child, (prevProps, nextProps) => {
// повернути true → пропси однакові → не ререндеримо
// повернути false → пропси змінилися → ререндеримо
return prevProps.id === nextProps.id;
});Зазвичай це використовується для складніших перевірок, але типово достатньо shallow compare.
Коли React.memo корисний
Використовуй, якщо:
- Компонент часто отримує однакові пропси;
- Його рендеринг важкий (складна розмітка, розрахунки);
- Він не залежить від стану батька напряму;
- Ти контролюєш стабільність посилань (
useCallback,useMemo).
Коли React.memo не потрібен
Не використовуй, якщо:
- Компонент завжди отримує нові пропси (або контекст);
- Компонент маленький і рендериться швидко;
- Оптимізація не дає реальної вигоди (shallow compare може бути дорожчим).
Підсумок: у чому суть
Що робить React.memo | Що буде без нього |
|---|---|
| Порівнює пропси і пропускає повторний рендер | Компонент ререндериться при кожному рендері батька |
| Працює лише при незмінних пропсах | React викликає компонент заново завжди |
| Працює поверхнево (за посиланнями) | React не робить оптимізацій |
Ефективний разом з useCallback і useMemo | Зайві ререндери дочірніх компонентів |
Приклад оптимізованої зв'язки
const Child = React.memo(({ onClick, label }) => {
console.log('Child render');
return <button onClick={onClick}>{label}</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => console.log('click'), []);
console.log('Parent render');
return (
<>
<Child onClick={handleClick} label="Press me" />
<button onClick={() => setCount(c => c + 1)}>+</button>
</>
);
}Тут:
Childобгорнутий уReact.memo;handleClickстабілізований черезuseCallback;- Тому
Childне ререндериться при змініcount.
Коротко
| Питання | Відповідь |
|---|---|
Що робить React.memo()? | Кешує результат рендеру функціонального компонента і пропускає повторний виклик, якщо пропси не змінилися |
| Як порівнює пропси? | Поверхнево (shallow compare) |
| Що якщо не вказати? | Компонент ререндериться щоразу при ререндері батька |
| Коли корисний? | Коли пропси рідко змінюються і компонент дорогий |
| Коли не потрібен? | Коли компонент легкий або отримує нові пропси завжди |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.