Принципы декомпозиции
📚 Введение
Компонент — это строительный блок, который может состоять из нескольких мелких компонентов. Такой подход позволяет превратить сложный и объёмный фрагмент кода в один цельный блок.
Зачем это нужно?
Во-первых, чтобы разработчику было проще ориентироваться в большом объёме кода. Мы можем
сгруппировать связанные между собой строки, функции, данные и логику в единый блок — там, где есть
high cohesion (высокая связанность).
Во-вторых, компонент получает имя, отражающее его назначение. Например:
- список треков —
TrackList; - карточка трека —
TrackDetail; - шапка сайта —
Header.
На странице может быть несколько таких фрагментов, каждый из которых удобно выделить в отдельный компонент.
Наконец, компоненты снижают ментальную нагрузку и дают возможность многократного использования. В них может быть заложена определённая функциональность, которую легко применять повторно в разных местах проекта.
1. React Component
React Component — это функция, имя которая начинается с заглавной буквы и которая возвращает какой
либо JSX.
К примеру, у нас есть компонент App, который мы импортируем в главный файл main.tsx. Внутри App
инкапсулирована (спрятана) логика и структура сайта: например, отображение списка треков или выбор
конкретного трека.
Файл main.tsx ничего об этом не знает. Его задача — запустить процесс: отрендерить компонент App,
в котором уже заложены функциональность и структура JSX-тегов для отображения на странице.
2. Создаем новый компонент
И так создадим новый компонент MainPage прям в файле main.tsx вместо компоненты App.
3. Создаем структуру приложения
Мы хотим создать понятную структуру сайта, поэтому разделим его на отдельные блоки (компоненты). Это упрощает восприятие кода и позволяет легко понимать, какой элемент за что отвечает.
И так получаем ошибки так как таких компонент не существует поэтому создадим компоненты
И так мы создали структуру и уже можем увидеть что все отобразилось на экране

Далее вынесем компоненты в отдельную папку components к примеру с помощью виделения компоненты и
затем с помощью клавиши f6 или сочетания клавиш fn + f6, ну или вручную можно создать компонент
внутри папки components.
- Footer.tsx
- Header.tsx
- PageTitle.tsx
- SidebarMenu.tsx
- TrackDetail.tsx
- TrackList.tsx
- main.tsx
- ...
4. Состояние в компонентах
Добавим useState в компонентах TrackList и TrackDetail
И также вызовем компонент TrackDetail в MainPage дважды.
В примере выше мы вызываем компонент TrackList и дважды — TrackDetail.
Так как в обоих компонентах используется useState, при каждом их рендере для компоненты создаётся
собственная ячейка состояния в памяти (внутри соответствующего FiberNode).
Поэтому:
- для
TrackListбудет создан одинcounter; - для каждого вызова
TrackDetailсоздаётся свой независимыйcounter.
В итоге, если кликнуть по первой отрисованной TrackDetail, значение счётчика изменится только у
неё. Вторая отрисовка останется со своим отдельным состоянием.

Таким образом, каждое использование компонента формирует собственный экземпляр состояния. Сколько
раз мы не вызовем TrackDetail, для каждого рендера React создаст отдельное состояние, которое
хранится и управляется внутри компоненты через FiberNode.
5. Переносим логику и отрисовку треков в TrackList
Постепенно анализируя, какие данные и разметка нужны для отображения треков, мы переносим всю
соответствующую логику и JSX из компоненты App в специально созданный компонент TrackList.
Теперь мы можем увидеть, как треки отображаются внутри компоненты TrackList. Вся логика и JSX,
связанные с треками, инкапсулированы (спрятаны) внутри этой компоненты.
Компонент MainPage при этом не знает ничего о запросах на сервер и деталях работы с треками — она
просто использует TrackList как готовый блок.

Продолжим работу с компонентом и перенесем состояние для выбора трека которое было при нажатии на
title трека.
6. Загрузка деталей трека
Для лучшего отображения треков и деталей трека на странице объединим в один блок TrackList и
TrackDetail.
Далее выносим из компоненты App всю логику, связанную с TrackDetail. Так как состояние
selectedTrackId мы перенесли в TrackList, в этой точке мы теряем к нему доступ. Чтобы временно
сохранить работоспособность и проверить корректность запросов, создаём заглушку в виде переменной
selectedTrackId.
И можем увидеть такой результат

7. Компонент PageTitle
При дальнейшем разборе компонента TrackList замечаем, что в нем лишним оказалось имя страницы.
Вынесем его в отдельный созданный компонент PageTitle, чтобы TrackList отвечал только за
отображение треков, а имя страницы обрабатывалось отдельно.
Заключение: Декомпозирование кода на компоненты играет ключевую роль. Оно упрощает чтение и поддержку проекта: сегодня в компоненте может быть одна строка, а завтра — десятки. Когда код разделён на компоненты, структура приложения становится прозрачнее, легче находить нужные части и вносить изменения, не усложняя остальную кодовую базу.
🏠 Домашнее задание
Цель задания:
-
Освоить принципы декомпозиции React-приложений и научиться выделять независимые компоненты с высокой внутренней связанностью и низкой связанностью между собой.
-
Разбить большой компонент
Appна отдельные компоненты, следуя принципам высокой связанности (high cohesion) внутри компонентов и низкой связанности (low coupling) между компонентами.
Задача 1
Создать структуру главной страницы
Создай компонент MainPage, который будет содержать общую структуру приложения
Задача 2
Создание компонент
Создай заглушки для компонент по аналогии с Header.tsx и убедись, что компоненты отрисовываются
Итоговый результат 🚀

Задача 3
PageTitle
В компоненте PageTitle.tsx замени div на заголовок первого уровня и в качестве текста напиши
Trelly
Итоговый результат 🚀

Задача 4
TasksList
Перенеси код из компонента App.tsx в TasksList.tsx, который должен содержать:
- Состояние
tasks - Логику загрузки всех задач
- Состояние
selectedTaskIdдля отслеживания выбранной задачи - Отрисовку списка задач
- Временно закомментируй
setBoardId(task.attributes.boardId)
Итоговый результат 🚀

Задача 5
TaskDetails
Перенеси код из компонента App.tsx в TaskDetails.tsx, который должен содержать:
- Состояние
selectedTask - Логику загрузки выбранной задачи
- Отображение деталей выбранной задачи
❗ Поскольку тема пропсов и колбэков будет в следующих уроках, пока что в TaskDetails создай
константы selectedTaskId и boardId. Значения возьми из network вкладки
const selectedTaskId = '4f310604-82b5-4afd-b9a4-ddf12dfac0a3'const boardId = '13923117-72de-4788-a7f0-4c42f162a5ab'

Итоговый результат 🚀

Критерии успеха
- ✅ Каждый компонент содержит только связанную между собой логику
- ✅ В
TasksListнаходится только логика работы со списком задач - ✅ В
TaskDetailsнаходится только логика работы с деталями задачи - ✅ Компоненты можно использовать независимо друг от друга
- ✅ Код легко читается и понимается
- ✅ При открытии любого компонента сразу понятно, за что он отвечает
🔶 Это домашнее задание основано на реальном процессе разработки: каждый день тысячи разработчиков сталкиваются с необходимостью разбивать большие компоненты на мелкие. От этого умения зависит читаемость кода и возможность работы в команде.
🔶 Навык декомпозиции - это то, что отличает junior-разработчика от middle. Компании готовы платить больше тем, кто умеет структурировать код так, чтобы его могли легко поддерживать другие программисты.
🔶 Каждый компонент, который ты выделишь в этом задании, - это маленький шаг к пониманию архитектуры. Через несколько месяцев ты будешь проектировать целые приложения, а начинается всё с умения правильно разбить один большой компонент.
🔶 Не переживай, если поначалу покажется сложным определить границы компонентов. Это приходит с опытом. Главное - начать экспериментировать и не бояться создавать "слишком много" мелких компонентов.


