Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що робить React.memo()?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)`React.memo()` - це **обгортка для функціонального компонента**, яка каже React: «Якщо пропси не змінилися - не ререндер цей компонент повторно». **Ключове:** React порівнює пропси поверхнево (shallow compare); без `React.memo` компонент ререндериться щоразу при ререндері батька, навіть якщо його пропси не змінилися.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що робить `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) | | Що якщо не вказати? | Компонент ререндериться щоразу при ререндері батька | | Коли корисний? | Коли пропси рідко змінюються і компонент дорогий | | Коли не потрібен? | Коли компонент легкий або отримує нові пропси завжди |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.