Розуміння вашого UI як дерева
React-застосунок формується великою кількістю компонентів, які вкладені один в одного. Як React відстежує структуру компонентів у вашому застосунку?
Інтерфейс користувача (далі — UI) моделюється у вигляді дерева у React і багатьох інших UI-бібліотеках. Думати про ваш застосунок як про дерево — корисно, щоб розуміти зв’язки між компонентами. Це розуміння допоможе вам далі у налагодженні певних моментів як продуктивність та управління станом.
Ви дізнаєтесь
- Як React “бачить” структури компонентів
- Що таке дерево рендерингу і чим воно корисне
- Що таке дерево залежностей модулів і чим воно корисне
Ваш UI у вигляді дерева
Дерева є моделлю зв’язків між елементами, і UI часто представлений за допомогою деревоподібних структур. Наприклад, браузери використовують деревоподібні структури для моделювання HTML (DOM) та CSS (CSSOM). Мобільні платформи також використовують дерева для представлення своєї ієрархії “екранів”.
Подібно до браузерів і мобільних платформ, React також використовує деревоподібні структури для управління та моделювання зв’язків між компонентами у React-застосунку. Ці дерева є корисними інструментами для розуміння того, як дані рухаються через React-застосунок і як оптимізувати рендеринг та розмір застосунку.
Дерево рендерингу
Основна функція компонентів полягає у можливості створення компонентів з інших компонентів. Коли ми вкладаємо компоненти, у нас з’являється концепція батьківських і дочірніх компонентів, де кожен батьківський компонент сам може бути дочірнім компонентом іншого компонента.
Коли ми рендеримо React-застосунок, ми можемо моделювати ці зв’язки у вигляді дерева, яке називається деревом рендерингу.
Ось застосунок React, який рендерить цитати, що надихають.
import FancyText from './FancyText'; import InspirationGenerator from './InspirationGenerator'; import Copyright from './Copyright'; export default function App() { return ( <> <FancyText title text="Застосунок 'Натхнення'" /> <InspirationGenerator> <Copyright year={2004} /> </InspirationGenerator> </> ); }
З прикладу застосунку ми можемо побудувати вищеописане дерево рендерингу.
Дерево складається з вузлів, кожен з яких відповідає певному компоненту. App
, FancyText
, Copyright
— це приклади кількох вузлів у нашому дереві.
Кореневий вузол у дереві рендерингу React — це кореневий компонент застосунку. У цьому прикладі кореневим компонентом є App
, і це перший компонент, який React рендерить. Кожна стрілка у дереві напрямлена від батьківського до дочірнього компонента.
Deep Dive
У наведеному вище дереві рендерингу не згадуються HTML-теги, які кожен компонент рендерить. Це тому, що дерево рендерингу складається лише з компонентів React.
React як UI-фреймворк є платформонезалежним. На сайті uk.react.dev ми демонструємо приклади, які рендеряться для вебу, що використовує HTML-розмітку як свої UI-примітиви. Але React-застосунок може так само рендеритися для мобільної або стаціонарної платформи, що може використовувати інші UI-примітиви, як-от UIView або FrameworkElement.
Ці платформові UI-примітиви не є частиною React. Дерева рендерингу React можуть надавати інформацію про наш React-застосунок незалежно від того, для якої платформи він рендериться.
Дерево рендерингу відповідає одному проходу рендеру React-застосунку. За допомогою умовного рендерингу батьківський компонент може відображати різних дітей залежно від переданих даних.
Ми можемо оновити застосунок, щоб умовно відрендерити або цитату, або колір, що надихає.
import FancyText from './FancyText'; import InspirationGenerator from './InspirationGenerator'; import Copyright from './Copyright'; export default function App() { return ( <> <FancyText title text="Застосунок 'Натхнення'" /> <InspirationGenerator> <Copyright year={2004} /> </InspirationGenerator> </> ); }
У цьому прикладі залежно від того, що є inspiration.type
, ми можемо відрендерити або <FancyText>
, або <Color>
. Дерево рендерингу може бути різним для кожного проходу рендеру.
Хоча дерева рендерингу можуть відрізнятися між різними проходами рендеру, вони загалом корисні для ідентифікації внутрішніх (top-level) та зовнішніх (leaf) компонентів у React-застосунку. Внутрішні компоненти — це компоненти, ближчі до кореневого компонента, які впливають на продуктивність рендерингу всіх компонентів під ними і часто є найбільш складними. Зовнішні компоненти, або листи, знаходяться в нижній частині дерева і не мають дочірніх компонентів та часто піддаються повторному рендерингу.
Ідентифікація цих категорій компонентів корисна для розуміння потоку даних (data flow) та продуктивності вашого застосунку.
Дерево залежностей модуля
Ще одним типом зв’язків у React-застосунку, що можуть бути змодельовані за допомогою дерева, є залежності модулів застосунку. Коли ми виносимо наші компоненти та логіку в окремі файли, ми створюємо JS-модулі, з яких можна експортувати компоненти, функції або константи.
Кожен вузол у дереві залежностей модулів — це модуль, а кожна гілка відповідає оператору import
у цьому модулі.
Якщо ми візьмемо попередній застосунок “Натхнення”, ми можемо побудувати дерево залежностей модулів, або скорочено — дерево залежностей.
Кореневий вузол дерева — це кореневий модуль, відомий також як файл точки входу. Зазвичай це модуль, який містить кореневий компонент.
Порівнюючи з деревом рендерингу цього ж застосунку, бачимо схожі структури з деякими ключовими відмінностями:
- Вузли, які утворюють дерево, відповідають модулям, а не компонентам.
- Модулі, що не містять компонентів, як-от
inspirations.js
, також є у цьому дереві. Дерево рендерингу охоплює лише компоненти. Copyright.js
розташований безпосередньо підApp.js
, але в дереві рендерингу компонентCopyright
з’являється як дочірній елементInspirationGenerator
. Це тому, щоInspirationGenerator
приймає JSX як проп children, тому він рендеритьCopyright
як дочірній компонент, а не імпортує модуль.
Дерева залежностей корисні для визначення, які модулі необхідні для запуску вашого React-застосунку. Під час побудови готового до впровадження React-застосунку зазвичай є етап, який запакує (bundle) весь необхідний JavaScript-код для доставлення клієнту. Інструмент, що за це відповідає, називається бандлер, і бандлери використовують дерево залежностей для визначення, які модулі повинно бути включено.
Відповідно до того, як зростає ваш застосунок, збільшується і розмір запакованого застосунку — бандлу. Великі розміри бандлів є “дорогими” для завантаження та виконання клієнтом. Великі розміри бандлів можуть затримувати час відображення вашого UI. Розуміння дерева залежностей вашого застосунку може допомогти з налагодженням цих проблем.
Recap
- Дерева — це поширений спосіб представлення зв’язків між сутностями. Часто вони використовуються для моделювання UI.
- Дерева рендерингу відображають вкладені зв’язки між компонентами React у межах одного рендеру.
- З умовним рендерингом дерево рендерингу може змінюватися між різними рендерами. Залежно від різних значень пропсів компоненти можуть рендерити різні дочірні компоненти.
- Дерева рендерингу допомагають ідентифікувати, які компоненти є внутрішніми, а які — зовнішніми (листи). Внутрішні компоненти впливають на продуктивність рендерингу всіх компонентів-нащадків, а компоненти-листи часто піддаються повторному рендерингу. Їх ідентифікація корисна для розуміння та налагодження продуктивності рендерингу.
- Дерева залежностей відображають залежності модулів у React-застосунку.
- Дерева залежностей використовуються бандлерами, щоб запакувати необхідний код для доставлення застосунку.
- Дерева залежностей корисні для налагодження великих розмірів бандлів, які збільшують час до появи першого вмісту та показують можливі оптимізації відносно того, який код додається до бандлу.