Представление UI в виде дерева

Ваше приложение React формируется с множеством вложенных друг в друга компонентов. Как же React отслеживает структуру компонентов вашего приложения?

React, как и многие другие библиотеки, моделирует UI в виде дерева. Представив ваше приложение в виде дерева, вы сможете лучше понять взаимосвязь между компонентами, а так же это поможет вам в отладке будущих концепций, таких как: производительность и управление состоянием.

Вы узнаете

  • Как React «видит» структуру компонентов
  • Что такое дерево рендеринга и в чем его польза
  • Что такое дерево зависимостей модулей и в чем его польза

UI в виде дерева

Дерево — это модель отношений между элементами, и UI часто использует эту структуру. Например, браузеры используют тот же подход для построения HTML (DOM) и CSS (CSSOM). Мобильные платформы так же используют структуру дерева для своей иерархии.

Схема с тремя горизонтально расположенными секциями. В первом разделе вертикально расположены три прямоугольника: 'Component A', 'Component B', и 'Component C'. Переход к следующей панели — это стрелка с логотипом React сверху и надписью 'React'. Средний раздел содержит дерево компонентов с корнем, обозначенным 'A', и двумя дочерними элементами, обозначенными 'B' и 'C'. Переход к следующему разделу снова осуществляется с помощью стрелки с логотипом React сверху и надписью 'React'. Последний, третий раздел, представляет собой каркас браузера, содержащий дерево из 8 узлов, в котором выделено только подмножество (с указанием поддерева из среднего раздела).
Схема с тремя горизонтально расположенными секциями. В первом разделе вертикально расположены три прямоугольника: 'Component A', 'Component B', и 'Component C'. Переход к следующей панели — это стрелка с логотипом React сверху и надписью 'React'. Средний раздел содержит дерево компонентов с корнем, обозначенным 'A', и двумя дочерними элементами, обозначенными 'B' и 'C'. Переход к следующему разделу снова осуществляется с помощью стрелки с логотипом React сверху и надписью 'React'. Последний, третий раздел, представляет собой каркас браузера, содержащий дерево из 8 узлов, в котором выделено только подмножество (с указанием поддерева из среднего раздела).

React создаёт UI-дерево из ваших компонентов. В этом случае дерево UI используется для последующего рендеринга в DOM.

React, так же как браузеры и мобильные платформы, использует структуру дерева для управления и построения связи между компонентами. Эти деревья являются полезным инструментом и помогут вам понять как данные проходят через приложение React, как оптимизировать рендеринг и размер приложения.

Дерево рендеринга

Основной особенностью компонентов считается возможность составлять одни компоненты из других. Когда мы вкладываем компоненты, у нас есть концепция родительских и дочерних компонентов, где каждый родительский компонент сам может быть дочерним по отношению к другому.

Когда мы рендерим React-приложение, мы можем смоделировать эти связи в виде дерева, известного как дерево рендеринга.

Вот пример приложения React, которое отображает вдохновляющие цитаты.

import FancyText from './FancyText';
import InspirationGenerator from './InspirationGenerator';
import Copyright from './Copyright';

export default function App() {
  return (
    <>
      <FancyText title text="Get Inspired App" />
      <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.

Как UI-фреймворк, React является платформонезависимым. В документации мы демонстрируем примеры рендеринга в web, где в качестве примитивов UI используется разметка HTML. Но приложение React так же может запускаться на мобильных или десктоп платформах, которые используют другие UI-примитивы, такие как: UIView или FrameworkElement.

Но примитивы на этих платформах не являются частью React. Его дерево может давать представление о вашем приложении независимо от того, на какой платформе запускается ваше приложение.

Дерево рендеринга представляет собой одиночный рендеринг приложения React. При условном рендеринге родительский компонент может рендерить разные дочерние компоненты в зависимости от переданных данных.

Мы можем обновить наше приложение, чтобы оно по условию отображало либо вдохновляющую цитату, либо цвет.

import FancyText from './FancyText';
import InspirationGenerator from './InspirationGenerator';
import Copyright from './Copyright';

export default function App() {
  return (
    <>
      <FancyText title text="Get Inspired App" />
      <InspirationGenerator>
        <Copyright year={2004} />
      </InspirationGenerator>
    </>
  );
}

График дерева с шестью узлами. Верхний узел дерева помечен как 'App'. От него ведутся две стрелки к узлам с метками 'InspirationGenerator' и 'FancyText'. Стрелки представляют собой сплошные линии и помечены словом 'renders'. Узел InspirationGenerator имеет три стрелки, две из которых пунктирны и помечены надписью 'renders?'. Они ведут к узлам 'FancyText' и 'Color'. Последняя стрелка указывает на узел с надписью 'Copyright', она сплошная и отмечена надписью 'renders'.
График дерева с шестью узлами. Верхний узел дерева помечен как 'App'. От него ведутся две стрелки к узлам с метками 'InspirationGenerator' и 'FancyText'. Стрелки представляют собой сплошные линии и помечены словом 'renders'. Узел InspirationGenerator имеет три стрелки, две из которых пунктирны и помечены надписью 'renders?'. Они ведут к узлам 'FancyText' и 'Color'. Последняя стрелка указывает на узел с надписью 'Copyright', она сплошная и отмечена надписью 'renders'.

При условном рендеринге, в разных случаях, дерево рендеринга может строить разные компоненты.

В данном случае, мы рендерим <FancyText> или <Color> в зависимости от inspiration.type. При каждом рендеринге дерево может быть разным.

Хотя деревья рендеринга могут различаться в зависимости от этапа рендеринга, обычно они полезны для определения того, что представляют собой компоненты верхнего уровня и конечные компоненты в приложении React. Компоненты верхнего уровня — это те, которые находятся ближе к корневому компоненту. Они влияют на производительность рендеринга всех дочерних компонентов, и часто содержат наибольшую сложность. Конечные компоненты находятся в нижней части дерева. Они не имеют дочерних компонентов и часто рендерятся повторно.

Определение того, к какой категории относится компонент поможет вам лучше понять поток данных и улучшнить производительность вашего приложения.

Дерево зависимостей модулей

Еще одна связь в приложении React, которую можно смоделировать с помощью дерева, — это зависимости модулей приложения. Разбивая компоненты и логику на отдельные файлы, мы создаем JS-модули, в которые можно экспортировать компоненты, функции или константы.

Каждый узел в дереве зависимостей модулей является модулем, а каждую ветвь представляет import.

Если мы возьмем предыдущее приложение с вдохновляющими цитатами, мы сможем построить дерево зависимостей модулей.

График дерева с семью узлами. Каждый узел помечен именем модуля. Верхний узел дерева помечен как 'App.js' и от него идут три стрелки, указывающие на модули 'InspirationGenerator.js', 'FancyText.js' и 'Copyright.js'. Стрелки представляют собой сплошные линии и помечены словом 'import'. Из узла 'InspirationGenerator.js' ведутся ещё три стрелки, которые указывают на три модуля: 'FancyText.js', 'Color.js' и 'Inspirations.js'. Стрелки сплошные и также помечены словом 'import'.
График дерева с семью узлами. Каждый узел помечен именем модуля. Верхний узел дерева помечен как 'App.js' и от него идут три стрелки, указывающие на модули 'InspirationGenerator.js', 'FancyText.js' и 'Copyright.js'. Стрелки представляют собой сплошные линии и помечены словом 'import'. Из узла 'InspirationGenerator.js' ведутся ещё три стрелки, которые указывают на три модуля: 'FancyText.js', 'Color.js' и 'Inspirations.js'. Стрелки сплошные и также помечены словом 'import'.

Дерево зависимостей модулей для приложения с вдохновляющими цитатами.

Корневым узлом дерева является корневой модуль, он же файл точки входа. Часто это модуль, содержащий корневой компонент.

Сравнив с деревом рендеринга, мы увидим схожие структуры и некоторые заметные различия:

  • Узлы, составляющие дерево, представляют собой модули, а не компоненты.
  • Модули которые не являются компонентами, такие как inspirations.js, также представлены в этом дереве. А дерево рендеринга инкапсулирует только компоненты.
  • Copyright.js появляется под App.js. Но в дереве рендеринга Copyright отображается как дочерний элемент InspirationGenerator. Это связано с тем, что Inspiration Generator принимает JSX в качестве дочерних пропсов, поэтому он отображает Copyright как дочерний компонент, но он не импортирует его.

Дерево зависимостей помогает определить какие модули необходимы для запуска вашего React-приложения. При создании приложения для продакшена есть этап сборки, на котором весь необходимый JavaScript будет отправлен клиенту. На этом этапе сборщик пакетов использует дерево зависимостей для того, чтобы определить какие модули содержит проект.

По мере роста вашего приложения часто увеличивается и размер сборщика. При больших размерах требуется больше затрат для загрузки и запуска клиента, а так же это может задерживать прорисовку вашего UI. Понимание же дерева зависимостей вашего приложения может помочь в отладке и устранении этих проблем.

Recap

  • Деревья — это распространенный способ показать отношения между сущностями. Они очень часто используются для построения UI.
  • Деревья рендеринга представляют собой отношения между вложенными компонентами React в рамках одной отрисовки.
  • С отрисовкой по условию, дерево рендеринга может меняться при разных запусках. В зависимости от пропсов, компоненты могут отображать разные дочерние компоненты.
  • Деревья рендеринга помогают определить, что такое компоненты верхнего уровня и конечные компоненты. Компоненты верхнего уровня влияют на производительность отрисовки всех компонентов, находящихся под ними, а конечные компоненты часто перерисовываются повторно. Их выявление поможет вам для понимания и отладки производительности рендеринга.
  • Дерево зависимостей — это зависимость модулей в приложении React.
  • Деревья зависимостей пользуются инструментами сборки для объединения необходимого кода для отправки приложения.
  • Деревья зависимостей полезны для отладки пакетов больших размеров, которые замедляют прорисовку и предоставляют возможности для оптимизации.