Skip to main content

Що робить React.memo()?

Що робить React.memo()

React.memo() - це обгортка для функціонального компонента, яка каже React:

«Якщо пропси не змінилися - не ререндер цей компонент повторно.»


Синтаксис

javascript
const MemoizedComponent = React.memo(MyComponent);

або одразу:

javascript
export default React.memo(function MyComponent(props) { return <div>{props.value}</div>; });

Як це працює

React при кожному рендері порівнює пропси нового і попереднього виклику компонента. Якщо пропси рівні за поверхневим порівнянням (shallow comparison):

  • компонент не викликається повторно;
  • повертається попереднє відрендерене дерево.

Приклад:

javascript
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> </> ); }

Що відбудеться:

javascript
Parent render Child render ← перший рендер Parent render ← після кліку (Child не ререндериться)

React.memo помітив, що props.value не змінився → не став викликати компонент.


Якщо не вказати React.memo

Тоді щоразу, коли батько ререндериться, усі дочірні компоненти будуть викликатися заново - навіть якщо їхні пропси не змінилися.

javascript
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> </> ); }

Кожне натискання кнопки викликає:

javascript
Parent render Child render (зайвий рендер)

Як React.memo порівнює пропси

React робить поверхневе (shallow) порівняння:

  • порівнює примітиви (number, string, boolean) за значенням;
  • порівнює об'єкти/масиви/функції за посиланням.

Важливо

javascript
const data = { name: 'Tim' }; <MemoChild user={data} />

Навіть якщо об'єкт виглядає однаково, React побачить нове посилання на { name: 'Tim' } щорендеру, і MemoChild все одно перемалюється.

Рішення - мемоізувати об'єкт:

javascript
const data = useMemo(() => ({ name: 'Tim' }), []); <MemoChild user={data} />

Кастомна функція порівняння

Можна передати другий аргумент - функцію, яка сама вирішує, чи потрібно ререндерити:

javascript
const MemoChild = React.memo(Child, (prevProps, nextProps) => { // повернути true → пропси однакові → не ререндеримо // повернути false → пропси змінилися → ререндеримо return prevProps.id === nextProps.id; });

Зазвичай це використовується для складніших перевірок, але типово достатньо shallow compare.


Коли React.memo корисний

Використовуй, якщо:

  1. Компонент часто отримує однакові пропси;
  2. Його рендеринг важкий (складна розмітка, розрахунки);
  3. Він не залежить від стану батька напряму;
  4. Ти контролюєш стабільність посилань (useCallback, useMemo).

Коли React.memo не потрібен

Не використовуй, якщо:

  • Компонент завжди отримує нові пропси (або контекст);
  • Компонент маленький і рендериться швидко;
  • Оптимізація не дає реальної вигоди (shallow compare може бути дорожчим).

Підсумок: у чому суть

Що робить React.memoЩо буде без нього
Порівнює пропси і пропускає повторний рендерКомпонент ререндериться при кожному рендері батька
Працює лише при незмінних пропсахReact викликає компонент заново завжди
Працює поверхнево (за посиланнями)React не робить оптимізацій
Ефективний разом з useCallback і useMemoЗайві ререндери дочірніх компонентів

Приклад оптимізованої зв'язки

javascript
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)
Що якщо не вказати?Компонент ререндериться щоразу при ререндері батька
Коли корисний?Коли пропси рідко змінюються і компонент дорогий
Коли не потрібен?Коли компонент легкий або отримує нові пропси завжди

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.