Рендер і коміт
Перш ніж ваші компоненти відобразяться на екрані, їх повинен відрендерити React. Розуміння кроків цього процесу допоможе осмислити перебіг виконання вашого коду та пояснити його поведінку.
You will learn
- Що таке рендеринг у React
- Коли і чому React рендерить компонент
- Кроки відображення компонента на екрані
- Чому рендеринг не завжди призводить до оновлення DOM
Уявіть, що ваші компоненти — це кухарі на кухні, які створюють смачні страви з інгредієнтів. У такій історії React — це офіціант, який приймає від клієнтів замовлення та видає їм їжу. Цей процес замовлення та видавання UI складається з трьох кроків:
- Тригер рендеру (доставлення замовлення гостя на кухню)
- Рендер компонента (готування замовлення на кухні)
- Коміт у DOM (розміщення замовлення на столі гостя)
Illustrated by Rachel Lee Nabors
Крок 1: Тригер рендеру
Існує дві причини для рендерингу компонента:
- Це початковий рендер компонента.
- Було оновлено стан компонента (або одного з його предків).
Початковий рендер
Під час запуску застосунку необхідно викликати початковий рендер. Фреймворки та пісочниці іноді приховують цей код, але це насправді виклик createRoot
із передачею цільового вузла DOM і потім виклик методу render
із вашим компонентом:
import Image from './Image.js'; import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')) root.render(<Image />);
Спробуйте зробити root.render()
коментарем — і побачите, що компонент зник!
Повторний рендер під час оновлення стану
Після першого рендеру компонента ви можете збудити (trigger) подальші рендери, оновивши його стан за допомогою функції set
. Оновлення стану вашого компонента автоматично додає рендер до черги. (Уявіть відвідувача ресторану, який після першого замовлення замовляє чай, десерт та всяку всячину залежно від стану спраги чи голоду).
Illustrated by Rachel Lee Nabors
Крок 2: React рендерить ваші компоненти
Після тригера рендеру React викликає (calls) ваші компоненти, щоб з’ясувати, що виводити на екран. “Рендеринг” — це коли React викликає ваші компоненти.
- Під час початкового рендеру React викличе кореневий компонент.
- Для наступних рендерів React викликатиме функцію компонента, оновлення стану якого власне збудило рендер.
Цей процес є рекурсивним: якщо оновлений компонент повертає якийсь інший компонент, React буде рендерити цей компонент наступним, і якщо цей компонент також щось повертає, він буде рендерити той інший компонент наступним, і так далі. Процес триватиме доти, доки не залишиться вкладених компонентів, і React не знатиме точно, що саме має бути відображено на екрані.
У цьому прикладі React викличе Gallery()
й Image()
кілька разів:
export default function Gallery() { return ( <section> <h1>Скульптури, що надихають</h1> <Image /> <Image /> <Image /> </section> ); } function Image() { return ( <img src="https://i.imgur.com/ZF6s192.jpg" alt="'Рід квіткові' ('Floralis Genérica') — Едуардо Каталано (Eduardo Catalano): велетенська металева скульптура квітки зі світловідбивними пелюстками" /> ); }
- Під час початкового рендеру React створює вузли DOM для
<section>
,<h1>
і трьох тегів<img>
. - *Під час повторного рендеру React вираховує, які властивості елементів змінилися після попереднього рендеру. Він нічого не робить з цією інформацією до наступного кроку, фази коміту.
Deep Dive
Стандартна поведінка, яка полягає у рендерингу всіх компонентів, вкладених в оновлений компонент, не є оптимальною для продуктивності, якщо оновлений компонент знаходиться дуже високо в дереві. Якщо ви зіткнулися з проблемою продуктивності, є кілька варіантів її вирішення, що наведені в розділі “Продуктивність”. Не оптимізуйте передчасно!
Крок 3: React вносить зміни в DOM
Після рендерингу (виклику) ваших компонентів React модифікує DOM.
- Для початкового рендерингу React використовує API DOM
appendChild()
, щоб вивести на екран усі новостворені вузли DOM. - Для повторних рендерів React застосовує мінімально необхідні операції (обчислені під час рендерингу!), щоб оновити DOM відповідно до результату найсвіжішого рендерингу.
React змінює вузли DOM тільки тоді, коли є різниця між рендерами. Наприклад, ось компонент, який повторно рендериться щосекунди з різними властивостями, що передаються від батьківського компонента. Зверніть увагу, що можна додати текст у <input>
, оновивши його value
, але текст не зникає, коли компонент рендериться повторно:
export default function Clock({ time }) { return ( <> <h1>{time}</h1> <input /> </> ); }
Це працює, тому що на останньому кроці React оновлює лише вміст <h1>
новим time
. Він бачить, що <input>
з’являється у JSX у тому ж місці, що і минулого разу, тому React не чіпає <input>
або його value
!
Епілог: Малювання браузера
Коли рендеринг завершено і React оновив DOM, браузер перемальовує екран. Хоча цей процес відомий як “рендеринг браузера”, ми будемо називати його “малюванням” (“painting”), щоб уникнути плутанини в документації.
Illustrated by Rachel Lee Nabors