Skip to main content

Як React визначає, які компоненти потрібно оновити?

Ключова ідея

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 не знайдено

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

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

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