Практическая лаборатория 4 из 5

Компонентное дерево TaskFlow

Приложение — это дерево компонентов. Каждый компонент получает только нужные данные и передаёт события вверх.

Сначала аналогия. Представьте матрёшку или семейное дерево. Самая большая матрёшка внутри прячет поменьше, а та — ещё меньше. Так же и приложение: одна большая «коробка» внутри содержит несколько поменьше, и каждая из них — свои. Или как семья: есть бабушка (главная), у неё дети, у детей — внуки. Кто выше в дереве, тот «старше» и раздаёт указания вниз.
А что такое «компонент»? Это одна деталь конструктора (как кирпичик Lego). Из многих таких деталей собирают целую игрушку. Одна деталь умеет делать только свою маленькую работу: показать кнопку, вывести строчку списка, нарисовать форму. Собираем детали вместе — получаем приложение TaskFlow (список задач).

Что вы узнаете

💡 Не пытайтесь выучить всё сразу. Читайте по шагам — каждый шаг добавит по одной детали к картинке.

Шаг 1. Дерево компонентов

Изучите схему. Каждый цвет — тип компонента.

Как читать схему. Самый верхний узел — AppShell — это «бабушка» всего приложения. От неё вниз тянутся веточки: сначала общая рамка (Layout), потом страница задач (TaskPage), а внутри неё — конкретные мелочи: форма, фильтр и список с отдельными задачами. Чем глубже вложен узел, тем он «мельче» и проще.
  • AppShell
    • Header
    • MainLayout
      • Sidebar
      • TaskPage
        • TaskForm
        • FilterBar
        • TaskList
          • TaskItem
          • TaskItem
          • TaskItem
Оболочка — «футляр» всего приложения Layout — общая рамка/каркас страницы Страница — готовит данные для задач Контейнер списка — просто рисует список UI-компонент — маленькая деталь (кнопка, строка)
Аналогия цветов. Цвет — это «профессия» детали. Синие (Layout) строят стены дома, зелёные (контейнер) расставляют мебель, оранжевые (UI) — это выключатели и ручки. Всех их собирает воедино футляр AppShell.

Шаг 2. Заполните шаблон

Для каждого компонента запишите: какие данные он получает и какие события может инициировать.

Контекст. Сейчас вы — как конструктор, который раздаёт каждой детали её «паспорт»: что ей дадут на вход (данные) и на что она может нажать/сигналить (события). Это и есть описание интерфейса компонента.
Аналогия из жизни. Заполнить шаблон — как описать для каждого ребёнка его связь с родителем: данные приходят в почтовый ящик ребёнка (родитель опускает туда данные — данные вниз), а события — это когда ребёнок зовёт родителя (события вверх). У каждого своя роль, и путать их нельзя.

▶️ Пошаговый разбор, что делать:

  1. Возьмите список компонентов ниже (AppShell, Header, TaskPage и т.д.).
  2. Для каждого подумайте: что ему нужно получить, чтобы работать (данные).
  3. Подумайте: что он может сообщить наверх, когда пользователь что-то сделал (события).
  4. Запишите это вместо черточек __ в шаблоне.
AppShell:  данные=__, события=__
Header:    данные=__, события=__
TaskPage:  данные=__, события=__
TaskList:  данные=__, события=__
TaskItem:  данные=__, события=__
TaskForm:  данные=__, события=__
FilterBar: данные=__, события=__
Что увидит студент. Пока это просто текст-заготовка с пропусками. Вы сами впишете туда ответы. Правильный вариант — в Шаге 3, не подсматривайте раньше времени 😉
Подсказка. Заполните шаблон до того, как смотрите ответ ниже. Важно не запомнить, а понять логику.

Шаг 3. Проверьте себя

Сверьте свои ответы с карточками. Здесь показано, что реально получает и отдаёт каждый компонент.

Аналогия из жизни. Карточки — как почтовый ящик и звонок ребёнка в семье: входящие данные родитель опускает в почтовый ящик ребёнка (данные вниз), а исходящие события — это когда ребёнок зовёт родителя (события вверх). Обратите внимание: мелкие детали (TaskItem, TaskForm, FilterBar) сами ничего не хранят — они только показывают и сигналят наверх. Вся «кухня» сосредоточена в TaskPage.

Корень AppShell

Данные: user, theme, isAuthenticated
События: logout(), toggleTheme()

Страница TaskPage

Данные: tasks[], filter, searchQuery, status
События: handleCreate(), handleToggle(id), handleDelete(id)

Контейнер TaskList

Данные: tasks[] (уже отфильтрованный!), status
События: onToggle(id), onDelete(id)

UI TaskItem

Данные: task (один объект)
События: onToggle(id), onDelete(id)

UI TaskForm

Данные: isLoading
События: onSubmit({ title })

UI FilterBar

Данные: currentFilter, searchQuery
События: onFilterChange(f), onSearchChange(q)
Что важно запомнить. Заметьте: поле задачи называется completed (выполнена?), а не done. Слово done здесь зарезервировано для фильтра — чтобы показывать «все / активные / выполненные» задачи. Перепутаете — код перестанет работать.

Ключевые выводы

Правило.
  • TaskPage — единственный «умный» компонент. Он хранит состояние.
  • TaskItem не знает о сервере. Он получает готовый объект и вызывает onToggle(id).
  • Фильтрация происходит в TaskPage. TaskList получает уже отфильтрованный массив.
  • События всплывают вверх (events bubble up), данные текут вниз (data flows down).
Аналогия «почтовый ящик и звонок ребёнка». Представьте семью. Данные текут вниз — как в почтовый ящик ребёнка: родитель опускает туда данные (данные вниз). События всплывают вверх — как когда ребёнок зовёт родителя (события вверх): маленькая кнопка «готово» не меняет данные сама, а лишь зовёт родителя — «я нажата!», а умный TaskPage уже решает, что с этим делать.
Аналогия «кухня и официант». TaskPage — это кухня: там готовят (фильтруют) список задач. TaskList — официант: он не готовит, а просто относит уже готовое блюдо (отфильтрованный массив) клиенту на стол. Поэтому в TaskList написано «уже отфильтрованный!».

Интерактивная песочница

Попробуйте изменить структуру компонентов или данные:

Контекст. Ниже — живой пример на чистом JavaScript. Он показывает, как компоненты TaskItem и TaskList собирают список задач и выводят его на экран. Это упрощённая модель нашего дерева: здесь корень рисует заголовок и вызывает TaskList, а TaskList вызывает TaskItem для каждой задачи.
Аналогия из жизни. Песочница — это ваш рабочий верстак или кухонный стол для экспериментов. Хочешь — поменяй название задачи, хочешь — добавь новую строчку, хочешь — перекрась галочку. Если испортишь — ничего страшного: оригинал урока не пострадает, а ты просто нажмёшь «Запустить» и увидишь результат.

▶️ Пошаговый разбор, что делает этот код:

  1. Данные. Создаём массив tasks — три задачи, у каждой есть id, title и поле completed (выполнена или нет).
  2. TaskItem. Функция берёт одну задачу и возвращает готовый HTML-кусочек: зелёный фон и галочку «✓», если completed true, и серый фон с «○», если нет.
  3. TaskList. Берёт весь список, для каждой задачи вызывает TaskItem (через .map()) и склеивает результаты в один <ul>.
  4. Корень. Записывает в блок #app заголовок со счётчиком и собранный список. На экране появляются три задачи.

💡 Что увидит студент после нажатия «Запустить»: заголовок «Список задач (3)» и три строчки. Первая — зелёная с галочкой (выполнена), остальные — серые с кружком.

Песочница: нажми «Запустить» — и увидишь список задач TaskFlow, собранный из компонентов TaskList и TaskItem. Меняй код и запускай снова.
Песочница: дерево компонентов
Попробуйте сами. В массиве tasks поменяйте completed: false на completed: true у второй задачи и нажмите «Запустить» — строчка станет зелёной. Так вы на практике увидите, как данные (поле completed) влияют на то, что рисует компонент.

Лаборатория 4 из 5. ← Лаборатория 3 | Лаборатория 5 →

Куда дальше: теория компонентов и связи — в Уроке 3 и Уроке 4, а практика — практика к уроку 4.

📖 Глоссарий

ТерминЖизненная аналогияКоротко
КомпонентДеталь конструктора (кирпичик Lego)Одна маленькая часть приложения, умеющая делать только свою работу.
Дерево компонентовМатрёшка или семейное деревоКомпоненты вложены друг в друга: старшие содержат и кормят младших.
Input (входные данные)Почтовый ящик ребёнкаРодитель опускает данные вниз — ребёнок их получает и читает.
Output (событие вверх)Ребёнок зовёт родителяДочерний компонент сигналит наверх, что пользователь что-то сделал.
Signal (сигнал)Группа в мессенджереПри изменении значения все «подписчики» тут же получают весточку.
СобытиеЗвонок в дверьСообщение о действии: нажали кнопку, ввели текст, поставили галочку.
Состояние (state)Статус заказаТекущее положение дел: «в обработке / готов / ошибка».

🧠 Самопроверка

1. В компонентной архитектуре данные текут вниз, а события всплывают вверх. Верно или неверно?

2. Компонент TaskItem сам хранит список всех задач и решает, что с ними делать. Верно или неверно?

3. Поле задачи называется done, а не completed. Верно или неверно?

Прогресс курса