Розуміння вашого UI як дерева

React-застосунок формується великою кількістю компонентів, які вкладені один в одного. Як React відстежує структуру компонентів у вашому застосунку?

Інтерфейс користувача (далі — UI) моделюється у вигляді дерева у React і багатьох інших UI-бібліотеках. Думати про ваш застосунок як про дерево — корисно, щоб розуміти зв’язки між компонентами. Це розуміння допоможе вам далі у налагодженні певних моментів як продуктивність та управління станом.

You will learn

  • Як React “бачить” структури компонентів
  • Що таке дерево рендерингу і чим воно корисне
  • Що таке дерево залежностей модулів і чим воно корисне

Ваш UI у вигляді дерева

Дерева є моделлю зв’язків між елементами, і UI часто представлений за допомогою деревоподібних структур. Наприклад, браузери використовують деревоподібні структури для моделювання HTML (DOM) та CSS (CSSOM). Мобільні платформи також використовують дерева для представлення своєї ієрархії “екранів”.

Діаграма із трьох секцій, розташованих горизонтально. У першій секції розташовані вертикально три прямокутники з написами 'Component A', 'Component B' та 'Component C'. Перехід до наступної секції здійснюється за допомогою стрілки з логотипом React над нею та підписом 'React'. Середня секція містить дерево компонентів: корінь, підписаний як 'A', і його двоє дітей, підписані як 'B' і 'C'. Перехід до наступної секції також здійснюється за допомогою стрілки з логотипом React над нею та підписом 'React DOM'. Третя і остання секція — це ескіз браузера, що містить дерево з 8 вузлами, в якому виділено кольором лише піддерево (що вказує на піддерево з середнього розділу).
Діаграма із трьох секцій, розташованих горизонтально. У першій секції розташовані вертикально три прямокутники з написами 'Component A', 'Component B' та 'Component C'. Перехід до наступної секції здійснюється за допомогою стрілки з логотипом React над нею та підписом 'React'. Середня секція містить дерево компонентів: корінь, підписаний як 'A', і його двоє дітей, підписані як 'B' і 'C'. Перехід до наступної секції також здійснюється за допомогою стрілки з логотипом React над нею та підписом 'React DOM'. Третя і остання секція — це ескіз браузера, що містить дерево з 8 вузлами, в якому виділено кольором лише піддерево (що вказує на піддерево з середнього розділу).

React створює дерево UI із ваших компонентів. У цьому прикладі дерево UI потім використовується для рендерингу у DOM.

Подібно до браузерів і мобільних платформ, 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, він має дві стрілки, які ведуть до 'InspirationGenerator' та 'FancyText'. Стрілки позначені словом 'renders'. Вузол 'InspirationGenerator' також має дві стрілки, що вказують на вузли 'FancyText' та 'Copyright'.
Граф дерева з п'ятьма вузлами. Кожен вузол відповідає компоненту. Корінь дерева — це App, він має дві стрілки, які ведуть до 'InspirationGenerator' та 'FancyText'. Стрілки позначені словом 'renders'. Вузол 'InspirationGenerator' також має дві стрілки, що вказують на вузли 'FancyText' та 'Copyright'.

React створює дерево рендерингу — дерево UI, складене з відрендерених компонентів.

З прикладу застосунку ми можемо побудувати вищеописане дерево рендерингу.

Дерево складається з вузлів, кожен з яких відповідає певному компоненту. App, FancyText, Copyright — це приклади кількох вузлів у нашому дереві.

Кореневий вузол у дереві рендерингу React — це кореневий компонент застосунку. У цьому прикладі кореневим компонентом є App, і це перший компонент, який React рендерить. Кожна стрілка у дереві напрямлена від батьківського до дочірнього компонента.

Deep Dive

Де у дереві рендерингу HTML-теги?

У наведеному вище дереві рендерингу не згадуються 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>
    </>
  );
}

Граф дерева із шістьма вузлами. Кореневий вузол дерева позначений як 'App' і має дві стрілки, що ведуть до вузлів, позначених як 'InspirationGenerator' та 'FancyText'. Стрілки мають тверді лінії і позначені словом 'renders'. Вузол 'InspirationGenerator' також має три стрілки. Стрілки до вузлів 'FancyText' і 'Color' пунктирні і позначені як 'renders?'. Остання стрілка вказує на вузол, позначений як 'Copyright', і є твердою та позначена словом 'renders'.
Граф дерева із шістьма вузлами. Кореневий вузол дерева позначений як 'App' і має дві стрілки, що ведуть до вузлів, позначених як 'InspirationGenerator' та 'FancyText'. Стрілки мають тверді лінії і позначені словом 'renders'. Вузол 'InspirationGenerator' також має три стрілки. Стрілки до вузлів 'FancyText' і 'Color' пунктирні і позначені як 'renders?'. Остання стрілка вказує на вузол, позначений як 'Copyright', і є твердою та позначена словом 'renders'.

За допомогою умовного рендерингу, посеред різних рендерів, дерево рендерингу може рендерити різні компоненти.

У цьому прикладі залежно від того, що є inspiration.type, ми можемо відрендерити або <FancyText>, або <Color>. Дерево рендерингу може бути різним для кожного проходу рендеру.

Хоча дерева рендерингу можуть відрізнятися між різними проходами рендеру, вони загалом корисні для ідентифікації внутрішніх (top-level) та зовнішніх (leaf) компонентів у React-застосунку. Внутрішні компоненти — це компоненти, ближчі до кореневого компонента, які впливають на продуктивність рендерингу всіх компонентів під ними і часто є найбільш складними. Зовнішні компоненти, або листи, знаходяться в нижній частині дерева і не мають дочірніх компонентів та часто піддаються повторному рендерингу.

Ідентифікація цих категорій компонентів корисна для розуміння потоку даних (data flow) та продуктивності вашого застосунку.

Дерево залежностей модуля

Ще одним типом зв’язків у React-застосунку, що можуть бути змодельовані за допомогою дерева, є залежності модулів застосунку. Коли ми виносимо наші компоненти та логіку в окремі файли, ми створюємо JS-модулі, з яких можна експортувати компоненти, функції або константи.

Кожен вузол у дереві залежностей модулів — це модуль, а кожна гілка відповідає оператору import у цьому модулі.

Якщо ми візьмемо попередній застосунок “Натхнення”, ми можемо побудувати дерево залежностей модулів, або скорочено — дерево залежностей.

Граф дерева із сімома вузлами. Кожен вузол позначений назвою модуля. Кореневий вузол дерева позначений як 'App.js'. Від нього виходять три стрілки до модулів 'InspirationGenerator.js', 'FancyText.js' та 'Copyright.js', і ці стрілки позначені словом 'imports'. Від вузла 'InspirationGenerator.js' відходять три стрілки до трьох модулів: 'FancyText.js', 'Color.js' та 'inspirations.js'. Ці стрілки позначені словом 'imports'.
Граф дерева із сімома вузлами. Кожен вузол позначений назвою модуля. Кореневий вузол дерева позначений як 'App.js'. Від нього виходять три стрілки до модулів 'InspirationGenerator.js', 'FancyText.js' та 'Copyright.js', і ці стрілки позначені словом 'imports'. Від вузла 'InspirationGenerator.js' відходять три стрілки до трьох модулів: 'FancyText.js', 'Color.js' та 'inspirations.js'. Ці стрілки позначені словом 'imports'.

Дерево залежностей модулів для застосунку “Натхнення”.

Кореневий вузол дерева — це кореневий модуль, відомий також як файл точки входу. Зазвичай це модуль, який містить кореневий компонент.

Порівнюючи з деревом рендерингу цього ж застосунку, бачимо схожі структури з деякими ключовими відмінностями:

  • Вузли, які утворюють дерево, відповідають модулям, а не компонентам.
  • Модулі, що не містять компонентів, як-от inspirations.js, також є у цьому дереві. Дерево рендерингу охоплює лише компоненти.
  • Copyright.js розташований безпосередньо під App.js, але в дереві рендерингу компонент Copyright з’являється як дочірній елемент InspirationGenerator. Це тому, що InspirationGenerator приймає JSX як проп children, тому він рендерить Copyright як дочірній компонент, а не імпортує модуль.

Дерева залежностей корисні для визначення, які модулі необхідні для запуску вашого React-застосунку. Під час побудови готового до впровадження React-застосунку зазвичай є етап, який запакує (bundle) весь необхідний JavaScript-код для доставлення клієнту. Інструмент, що за це відповідає, називається бандлер, і бандлери використовують дерево залежностей для визначення, які модулі повинно бути включено.

Відповідно до того, як зростає ваш застосунок, збільшується і розмір запакованого застосунку — бандлу. Великі розміри бандлів є “дорогими” для завантаження та виконання клієнтом. Великі розміри бандлів можуть затримувати час відображення вашого UI. Розуміння дерева залежностей вашого застосунку може допомогти з налагодженням цих проблем.

Recap

  • Дерева — це поширений спосіб представлення зв’язків між сутностями. Часто вони використовуються для моделювання UI.
  • Дерева рендерингу відображають вкладені зв’язки між компонентами React у межах одного рендеру.
  • З умовним рендерингом дерево рендерингу може змінюватися між різними рендерами. Залежно від різних значень пропсів компоненти можуть рендерити різні дочірні компоненти.
  • Дерева рендерингу допомагають ідентифікувати, які компоненти є внутрішніми, а які — зовнішніми (листи). Внутрішні компоненти впливають на продуктивність рендерингу всіх компонентів-нащадків, а компоненти-листи часто піддаються повторному рендерингу. Їх ідентифікація корисна для розуміння та налагодження продуктивності рендерингу.
  • Дерева залежностей відображають залежності модулів у React-застосунку.
  • Дерева залежностей використовуються бандлерами, щоб запакувати необхідний код для доставлення застосунку.
  • Дерева залежностей корисні для налагодження великих розмірів бандлів, які збільшують час до появи першого вмісту та показують можливі оптимізації відносно того, який код додається до бандлу.