Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як React визначає, які компоненти потрібно оновити?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**React** не оновлює весь UI, а лише ті компоненти, у яких змінилися props, state або контекст. **Ключове:** щоб зрозуміти це, React використовує свій алгоритм узгодження (reconciliation algorithm), порівнюючи нове і старе дерево Virtual DOM.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Ключова ідея > React **не оновлює весь UI**, а **лише ті компоненти**, у яких змінилися **props**, **state** або **контекст**. > > Щоб зрозуміти це, React використовує свій **алгоритм узгодження (reconciliation algorithm)**. --- ## 1. Тригер оновлення Повторний рендер (а отже, потенційне оновлення компонента) може бути викликаний: 1. Зміною внутрішнього стану (useState, setState) 2. Зміною props, переданих від батьківського компонента 3. Зміною контексту (useContext) 4. Явним викликом forceUpdate() (у класових компонентах) Ці події запускають render phase - React знову викликає функцію-компонент (або render() у класі). --- ## 2. React будує нове дерево Virtual DOM React викликає всі задіяні компоненти і створює нове «віртуальне представлення» UI, тобто нове дерево Virtual DOM. Кожен JSX-елемент перетворюється на об'єкт на кшталт: ```javascript { type: 'div', key: null, props: { className: 'btn', children: 'Click me' } } ``` --- ## 3. React порівнює старе і нове дерево Тепер починається reconciliation (узгодження): 1. React бере старе дерево Virtual DOM (до оновлення). 2. Порівнює його з новим деревом, створеним після виклику render(). 3. Обчислює, які вузли змінилися - це процес diffing. --- ## 4. Правила, за якими React вирішує, що оновити ### Правило 1: порівняння за типом елемента Якщо **тип** (type) елемента **такий самий**, React **зберігає** старий DOM-вузол і **оновлює лише пропси**. ```javascript <div className="old" /> <div className="new" /> // same element ``` React просто оновить className, не перестворюючи елемент. Якщо тип змінився, React видаляє старий вузол і створює новий. ```javascript <div>...</div> <span>...</span> ``` Старий `<div>` буде видалено, `<span>` - створено заново. --- ### Правило 2: порівняння за key у списках Коли в тебе список компонентів: ```javascript {items.map(item => <Todo key={item.id} text={item.text} />)} ``` React використовує key, щоб зрозуміти, які елементи залишилися незмінними, а які нові / видалені / переміщені. - Якщо key збігається, елемент залишається. - Якщо key інший, React вважає його новим елементом. Це дозволяє не перестворювати весь список, а лише змінені елементи. --- ### Правило 3: порівняння пропсів і стану Якщо компонент того самого типу, але: - props змінилися (за значенням або посиланням), - або внутрішній state оновився, React **перемалює (re-render)** цей компонент, щоб перерахувати Virtual DOM. Якщо пропси не змінилися (і компонент не залежить від контексту), React може пропустити його перерендер (особливо за використання React.memo). --- ### Правило 4: використання shouldComponentUpdate / React.memo Для оптимізації React може запитати в компонента: > «Чи потрібно тобі перерендеритися?» - У класових компонентах - через shouldComponentUpdate(nextProps, nextState). - У функціональних - через React.memo(Component, areEqual). Якщо відповідь - «Ні, все те саме», React пропускає оновлення і не викликає render(). --- ## 5. React обчислює diff і оновлює лише змінені частини DOM Після порівняння React знає: - які компоненти мають оновитися; - які DOM-вузли потрібно перемалювати; - які залишити як є. Далі настає commit phase, де React: - застосовує ці мінімальні зміни до реального DOM; - викликає useLayoutEffect і useEffect. --- ## Ілюстрація процесу ```javascript State changed ↓ Component recreated the Virtual DOM ↓ React compared the old and new tree (reconciliation) ↓ Found the changed nodes ↓ Applied only the necessary changes to the DOM (commit phase) ``` --- ## Приклад ```javascript function App() { const [count, setCount] = useState(0); return ( <div> <Header /> <Counter value={count} /> <button onClick={() => setCount(c => c + 1)}>+</button> </div> ); } ``` - Змінився count, тому React викликає App() знову. - Створюється нове Virtual DOM. - React порівнює: - `<Header />` - ті самі пропси, не оновлюється. - `<Counter value={count} />` - змінилися пропси, оновлюється. - Оновлюється лише текст усередині `<Counter>`, усе інше залишається незмінним. --- ## Підсумок > React визначає, які компоненти потрібно оновити, за допомогою **reconciliation algorithm**: порівнюючи нове і старе дерево Virtual DOM та аналізуючи **тип, ключ, props і state**. | Що змінилося | React оновить? | Чому | |---|---|---| | state усередині компонента | Так | компонент перестворюється | | props від батьківського компонента | Так | нові значення пропсів | | Батьківський компонент, але не props дитини | Залежить | якщо не React.memo | | context | Так | нове значення контексту | | key елемента | Так | створюється новий елемент | | Нічого не змінилося | Ні | diff не знайдено |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.