Розуміння вашого інтерфейсу як дерева

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

React, як і багато інших бібліотек інтерфейсу користувача, моделює інтерфейс користувача як дерево. Уявлення вашого додатку у вигляді дерева корисно для розуміння взаємозв'язку між компонентами. Це розуміння допоможе вам налагодити майбутні концепції, такі як продуктивність та управління станами.

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

Ваш інтерфейс як дерево

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

Diagram with three sections arranged horizontally. In the first section, there are three rectangles stacked vertically, with labels 'Component A', 'Component B', and 'Component C'. Transitioning to the next pane is an arrow with the React logo on top labeled 'React'. The middle section contains a tree of components, with the root labeled 'A' and two children labeled 'B' and 'C'. The next section is again transitioned using an arrow with the React logo on top labeled 'React DOM'. The third and final section is a wireframe of a browser, containing a tree of 8 nodes, which has only a subset highlighted (indicating the subtree from the middle section).

React створює дерево інтерфейсу користувача з ваших компонентів. У цьому прикладі дерево інтерфейсу використовується для рендерингу в 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="Get Inspired App" />
      <InspirationGenerator>
        <Copyright year={2004} />
      </InspirationGenerator>
    </>
  );
}
export default function FancyText({title, text}) {
  return title
    ? <h1 className='fancy title'>{text}</h1>
    : <h3 className='fancy cursive'>{text}</h3>
}
import * as React from 'react';
import quotes from './quotes';
import FancyText from './FancyText';

export default function InspirationGenerator({children}) {
  const [index, setIndex] = React.useState(0);
  const quote = quotes[index];
  const next = () => setIndex((index + 1) % quotes.length);

  return (
    <>
      <p>Your inspirational quote is:</p>
      <FancyText text={quote} />
      <button onClick={next}>Inspire me again</button>
      {children}
    </>
  );
}
export default function Copyright({year}) {
  return <p className='small'>©️ {year}</p>;
}
export default [
  "Don’t let yesterday take up too much of today.” — Will Rogers",
  "Ambition is putting a ladder against the sky.",
  "A joy that's shared is a joy made double.",
  ];
.fancy {
  font-family: 'Georgia';
}
.title {
  color: #007AA3;
  text-decoration: underline;
}
.cursive {
  font-style: italic;
}
.small {
  font-size: 10px;
}
Tree graph with five nodes. Each node represents a component. The root of the tree is App, with two arrows extending from it to 'InspirationGenerator' and 'FancyText'. The arrows are labelled with the word 'renders'. 'InspirationGenerator' node also has two arrows pointing to nodes 'FancyText' and 'Copyright'.

React створює дерево рендерингу, дерево інтерфейсу, що складається з відрендерених компонентів.

На прикладі програми ми можемо побудувати наведене вище дерево рендерингу.

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

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

Де знаходяться HTML-теги у дереві рендерингу?

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

React, як фреймворк інтерфейсу користувача, не залежить від платформи. На react.dev ми показуємо приклади, які рендериться на вебі, де в якості примітивів інтерфейсу використовується HTML-розмітка. Але React-застосунок з такою ж ймовірністю може рендерити на мобільну або десктопну платформу, яка може використовувати інші примітиви інтерфейсу, такі як UIView або FrameworkElement.

Ці примітиви користувацького інтерфейсу платформи не є частиною 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>
    </>
  );
}
export default function FancyText({title, text}) {
  return title
    ? <h1 className='fancy title'>{text}</h1>
    : <h3 className='fancy cursive'>{text}</h3>
}
export default function Color({value}) {
  return <div className="colorbox" style={{backgroundColor: value}} />
}
import * as React from 'react';
import inspirations from './inspirations';
import FancyText from './FancyText';
import Color from './Color';

export default function InspirationGenerator({children}) {
  const [index, setIndex] = React.useState(0);
  const inspiration = inspirations[index];
  const next = () => setIndex((index + 1) % inspirations.length);

  return (
    <>
      <p>Your inspirational {inspiration.type} is:</p>
      {inspiration.type === 'quote'
      ? <FancyText text={inspiration.value} />
      : <Color value={inspiration.value} />}

      <button onClick={next}>Inspire me again</button>
      {children}
    </>
  );
}
export default function Copyright({year}) {
  return <p className='small'>©️ {year}</p>;
}
export default [
  {type: 'quote', value: "Don’t let yesterday take up too much of today.” — Will Rogers"},
  {type: 'color', value: "#B73636"},
  {type: 'quote', value: "Ambition is putting a ladder against the sky."},
  {type: 'color', value: "#256266"},
  {type: 'quote', value: "A joy that's shared is a joy made double."},
  {type: 'color', value: "#F9F2B4"},
];
.fancy {
  font-family: 'Georgia';
}
.title {
  color: #007AA3;
  text-decoration: underline;
}
.cursive {
  font-style: italic;
}
.small {
  font-size: 10px;
}
.colorbox {
  height: 100px;
  width: 100px;
  margin: 8px;
}
Tree graph with six nodes. The top node of the tree is labelled 'App' with two arrows extending to nodes labelled 'InspirationGenerator' and 'FancyText'. The arrows are solid lines and are labelled with the word 'renders'. 'InspirationGenerator' node also has three arrows. The arrows to nodes 'FancyText' and 'Color' are dashed and labelled with 'renders?'. The last arrow points to the node labelled 'Copyright' and is solid and labelled with 'renders'.

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

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

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

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

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

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

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

Якщо ми візьмемо попередній застосунок Inspirations, ми можемо побудувати дерево залежностей модулів, або дерево залежностей для стислості.

A tree graph with seven nodes. Each node is labelled with a module name. The top level node of the tree is labelled 'App.js'. There are three arrows pointing to the modules 'InspirationGenerator.js', 'FancyText.js' and 'Copyright.js' and the arrows are labelled with 'imports'. From the 'InspirationGenerator.js' node, there are three arrows that extend to three modules: 'FancyText.js', 'Color.js', and 'inspirations.js'. The arrows are labelled with 'imports'.

Дерево залежностей модулів для програми Inspirations.

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

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

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

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

З ростом вашої програми часто зростає і розмір пакета. Великі пакети є важкими для завантаження та запуску клієнтом. Великі розміри пакетів можуть затримати час відображення вашого інтерфейсу. Розуміння дерева залежностей вашої програми може допомогти у налагодженні цих проблем.

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