🏗️ Стейт менеджер на хуках / Business Logic Layer
Автор конспекта: Стогниева Виктория
🎯 Введение: Проблема "толстых" компонентов
В начале пути React-разработчика часто возникает ситуация, когда один компонент становится слишком большим и сложным. Такой компонент называют "толстым" (fat) — он берет на себя слишком много ответственности:
- 🧩 Отрисовка UI (визуализация) — генерирует JSX-разметку, видимую пользователю.
- 🔄 Управление состоянием (state management) — хранит и обновляет данные (например, список треков).
- 🌐 Выполнение запросов к API (API requests) — взаимодействует с сервером.
React — это лишь UI-библиотека. Она должна эффективно рендерить интерфейс, а не решать все
задачи приложения.
📉 Проблема: Смешение задач делает код:
- трудным для понимания,
- сложным в тестировании,
- неудобным для рефакторинга,
- непригодным для переиспользования.
⚙️ 1. Фундаментальный принцип: Разделение ответственности (Separation of Concerns)
🧠 Определение: Каждая часть системы должна решать одну четко определённую задачу.
💡 Вместо одного "толстого" компонента мы создаём несколько специализированных модулей, работающих вместе.
🔑 Преимущества:
- 🎯 Фокусировка внимания — можно сосредоточиться на конкретной задаче.
- 🧩 Легкий рефакторинг — изменения в API не затрагивают UI.
- 🔁 Переиспользование логики — один и тот же хук можно применять в разных компонентах.
- 🧪 Упрощение тестирования — UI и бизнес-логику тестируют отдельно.
🧱 2. Три слоя архитектуры React-приложения
Иерархия зависимостей:
UI → Бизнес-логика → Доступ к данным
Это обеспечивает устойчивость архитектуры — внутренние изменения не ломают внешний интерфейс.
🎨 2.1. Слой UI (Presentation Layer)
- 📋 Задача: отображение данных и реакция на действия пользователя.
- 🧱 Состав: React-компоненты с JSX.
- ✨ Результат: “тонкие” компоненты — не содержат логику, только визуализацию.
⚙️ 2.2. Слой бизнес-логики (Business Logic Layer)
- 🧠 Задача: управление состоянием и реализация бизнес-правил.
- 🪄 Реализация: кастомные хуки (
useTracks,useCounterи т.д.). - 🧩 Альтернативные названия:
domain,state layer,application logic layer.
🌐 2.3. Слой доступа к данным (Data Access Layer)
- 🔗 Задача: взаимодействие с сервером (API).
- 🧱 Состав: отдельные функции или объекты для запросов (
getTracksViaAPI). - 🕶️ Преимущество: UI не знает о структуре API, токенах и URL — всё инкапсулировано.
🪄 3. Кастомные хуки: Инструмент бизнес-логики
Кастомный хук — это способ вынести состояние и эффекты из компонентов, сохранив переиспользуемость.
📘 Правила:
- Это обычная JS-функция.
- Название начинается с
use(например,useTracks). - Внутри можно использовать другие React-хуки (
useState,useEffectи т.д.).
🧩 Важно: React связывает состояние не с хуком, а с компонентом, который его вызывает. Поэтому два компонента с одним хуком создают независимые состояния.
🔍 Пример:
useTracks:
- хранит состояние с треками (
useState); - загружает данные (
useEffect); - возвращает готовые данные компоненту.
⚖️ Сравнение:
Компонент стал тонким. Мозг не перегружен деталями. Только UI — это фантастика!
🧩 4. Практический пример: Рефакторинг компонента Counter
🧱 Исходная версия:
Компонент Counter хранит всё внутри себя (useState, onClick).
🔧 Этапы рефакторинга:
- ✂️ Создаём хук
useCounter— переносимuseStateиincrement()внутрь. - 🛡️ Инкапсулируем бизнес-логику — хук возвращает не
setCount, аincrement(). - ⏱️ Добавляем автосброс — в хуке через
useEffectиsetInterval. - ⚙️ Делаем хук гибким — добавляем параметр
startValue.
Теперь Counter занимается только отображением, а бизнес-логикой полностью внутри хука.
🧩 5. Практический пример: Рефакторинг MusicFan
🧭 Заключение: Преимущества правильной архитектуры
- ✅ Снижение когнитивной нагрузки — меньше деталей, легче понимать код.
- 🚀 Быстрое развитие —добавление фич без ломки архитектуры.
- 🏢 Готовность к enterprise-проектам — масштабируемая структура.
- 🤖 Совместимость с AI и командной работой — чистая архитектура понятна как людям, так и помощникам.
💎 Итог
Хорошая архитектура React-приложения строится на трёх китах:
- Разделение ответственности.
- Три слоя — UI, бизнес-логика, данные.
- Кастомные хуки как инструмент связи между слоями.
Делайте компоненты тонкими, а архитектуру — умной.
🏠 Домашнее задание
Цель задания: Научиться создавать кастомные хуки с гибкой конфигурацией
Задание 1
По аналогии как в видео необходимо доработать основное приложение Trelly, над которым мы закончили работать в 22 домашнем задании
1.1. TasksList
- Создай директорию bll на одном уровне с ui и dal.
- В bll директории создай файл useTasks.ts
- Из компонента TasksList.tsx вынеси логику в кастомный хук useTasks.ts
Пример структуры
Итоговый результат. Вынесли бизнес логику в кастомный хук, таски подгружаются как и прежде 🚀
1.2. TaskDetails
- В bll директории создай файл useTaskDetails.ts
- Из компонента TaskDetails.tsx вынеси логику в кастомный хук useTaskDetails.ts
- Переименуй selectedTask в taskDetails, чтобы название переменной было актуально и более семантично
Пример структуры
Итоговый результат. Вынесли бизнес логику в кастомный хук. При клике на таску подгружаются ее детали 🚀
1.3. MainPage
- В bll директории создай файл useTaskSelection.ts
- Из компонента MainPage.tsx вынеси логику в кастомный хук useTaskSelection.ts
Пример структуры
Итоговый результат. Вынесли бизнес логику в кастомный хук. Все работает как и прежде 🚀
Задание 2
Описание задачи
У тебя есть базовый хук useCounter с автоматическим сбросом. Твоя задача - добавить методы для
уменьшения счётчика и сброса к начальному значению.
Исходный код
Что нужно сделать
- Добавь в хук
useCounterдва новых метода:
dec- уменьшает счётчик на 1reset- сбрасывает счётчик к начальному значениюstartValue
- Обнови компонент
Counter:
- Отображай текущее значение счётчика в
<h2> - Добавь три кнопки: "Увеличить", "Уменьшить", "Сбросить"
Итоговый результат 🚀:

Задание 3
Описание задачи
Добавь возможность настраивать шаг увеличения/уменьшения.
Что нужно сделать
- Добавь в хук
useCounterвторой параметрstartStep(по умолчанию1):
- Методы
incиdecдолжны изменять счётчик на величинуstep
- Обнови компонент
Counter:
- Добавь еще один useState в котором будет храниться новый шаг
- Добавь кнопку "Установить шаг 5". При нажатии на кнопку пользователь увидит alert сообщающий о том, что шаг изменился на 5 и после этого счетчик должен изменять значение счетчика с новым шагом
Пример структуры
Итоговый результат 🚀

Задание 4
Описание задачи
Сделай время автосброса настраиваемым параметром хука.
Что нужно сделать
- Добавь в хук
useCounterтретий параметрautoResetTime(по умолчанию0):
- Если
autoResetTime > 0, счётчик автоматически сбрасывается через указанное время в миллисекундах - Если
autoResetTime === 0илиnull, автосброс отключен
autoResetTime должно принимать значение в секундах, а не милисекундах
- Создай два компонента для демонстрации:
Компонент Counter:
- Использует хук с параметрами:
startValue: 0,startStep: 1,autoResetTime: 3 - Отображает текст "⏰ Автосброс через 3 сек"
Компонент CounterWithoutAutoReset:
- Использует хук с параметрами:
startValue: 5,startStep: 5,autoResetTime: 0 - Отображает текст "🔒 Без автосброса"
- Создай страницу
CounterPageс обоими компонентами
Подсказки
- Используй условие внутри
useEffectдля проверкиautoResetTime > 0 - Только если условие выполняется, запускай
setInterval
Пример структуры
Итоговый результат 🚀

Задание 5 ⭐
⭐ Дополнительное задание со звездочкой. Проделывать по желанию. В дальнейших уроках про это будет рассказано
Описание задачи
Исправь утечку памяти в хуке useCounter, добавив очистку интервала.
Проблема
Сейчас в useEffect запускается setInterval, но он никогда не останавливается. Это приводит к
утечке памяти - интервал продолжает работать даже после размонтирования компонента.
Что нужно сделать
- Добавь cleanup function в
useEffect - Сохрани результат
setIntervalв переменнуюintervalId - Верни функцию из
useEffect, которая вызываетclearInterval(intervalId)
Подсказки
- Cleanup function вызывается автоматически при размонтировании компонента
- Прочитай про это в документации React: Synchronizing with Effects
Важно: Всегда очищай side-эффекты (интервалы, подписки, таймеры) в cleanup function, чтобы избежать утечек памяти и неожиданного поведения.
🔶 Думай как архитектор: разделяй и властвуй. Компонент не должен знать, как работает логика переключения, счётчика или таймера — он просто использует готовый интерфейс. Кастомный хук — это инструмент в твоём наборе. Меняй реализацию внутри хука без единого изменения в компонентах. 🎯
🔶 Тестирование становится проще. Вместо того чтобы тестировать одну и ту же логику в 5 разных компонентах, ты пишешь тесты один раз — для кастомного хука. Баг нашёлся? Фиксишь в одном месте, и он исчезает везде. Это как чинить водопровод в подвале, а не латать протечки на каждом этаже. 🔧


