React

Мыслить на React: декомпозиция UI

Новичок смотрит на макет из Figma и впадает в ступор: с чего начать? Появляется соблазн писать один огромный компонент на 400 строк, в который свалено всё. Через неделю в нём невозможно ничего найти, а любая правка ломает три других места. Команда React заметила эту боль и описала повторяемый метод из пяти шагов - 'Thinking in React'. Он превращает картинку в работающий интерфейс без хаоса: сначала структура, потом статика, и только в конце - состояние и интерактивность. Тот же путь проходит инженер в Meta, разбирая новую фичу.

  • Раздел 'Thinking in React' - часть официальной документации react.dev, рекомендованный старт для проектирования любой фичи
  • Дизайн в Figma с готовой иерархией слоёв естественно ложится на дерево компонентов React
  • Atomic Design (атомы, молекулы, организмы) - популярная в индустрии методология той же декомпозиции UI
  • Code review в командах часто начинается с вопроса 'правильно ли разбито на компоненты и где живёт состояние'

Предварительные знания

  • Компоненты и props: компонент-функция, данные текут вниз через props
  • Рендеринг списков через map для повторяющихся блоков интерфейса
  • Базовая идея состояния: данные, которые меняются от действий пользователя

Шаги 1-2: дерево компонентов и статичная версия

Первый шаг - разглядеть на макете границы компонентов. Ориентир тот же, что в проектировании функций: единственная ответственность. Если кусок интерфейса делает слишком много, его делят. Получается дерево: корневой компонент содержит дочерние, те - свои, и так далее. Совпадение с моделью данных - хороший знак: часто структура компонентов повторяет структуру JSON, который приходит с сервера.

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

На статичном этапе данные текут строго вниз через props. Состояние сознательно не добавляют: попытка одновременно строить дерево и продумывать интерактивность - частая причина запутанного кода у новичков.

По какому принципу макет разбивают на компоненты на первом шаге?

Шаг 3: минимальное состояние

Когда статичная версия готова, добавляется интерактивность. Для этого нужно найти минимальный набор состояния - тот минимум данных, который меняется и которого достаточно, чтобы описать весь интерфейс. Ключевое слово - минимальный: чем меньше состояния, тем меньше источников рассинхрона. Лишнее состояние - главный источник багов.

Чтобы понять, является ли что-то состоянием, проверяют по трём вопросам. Если данные приходят сверху через props - это не состояние. Если данные со временем не меняются - не состояние. Если их можно вычислить из других props или состояния - тоже не состояние, а производное значение, которое считают прямо при рендере.

  1. Приходит через props сверху? Значит, это не состояние, а данные родителя
  2. Остаётся неизменным со временем? Значит, это константа, а не состояние
  3. Можно вычислить из других состояния или props? Значит, это производное значение, его не хранят
  4. Если ни одно не подошло - это настоящее состояние

Хранить в состоянии то, что выводится из других данных - типичная ошибка. Например, держать отдельно total рядом с items. Тогда при изменении items приходится вручную пересчитывать total, и рано или поздно они разойдутся. Производные значения считают прямо при рендере.

Сумму корзины можно посчитать из списка товаров. Это состояние?

Шаги 4-5: где живёт состояние и обратный поток

Состояние найдено - осталось решить, в каком компоненте оно живёт. Правило: состояние размещают в ближайшем общем родителе всех компонентов, которым это состояние нужно. Если значение читают два соседних компонента, оно поднимается к их общему родителю, а оттуда спускается вниз через props. Так сохраняется один источник правды.

Пятый шаг добавляет обратный поток данных. Поле поиска живёт в SearchBar, а само значение хранится в родителе. Чтобы дочерний компонент мог изменить состояние родителя, родитель передаёт вниз функцию-колбэк. Ребёнок вызывает её при вводе, родитель обновляет своё состояние, и новое значение снова спускается вниз. Данные идут вниз, события - вверх.

Этот пятый шаг - и есть подъём состояния (lifting state up), которому посвящён отдельный урок. Здесь он показан как финальная часть единого метода проектирования, чтобы вся картина сложилась целиком.

В каком компоненте должно жить состояние, которое читают два соседних компонента?

Связь с другими темами

Этот урок - мост от статичных компонентов к интерактивным. Его шаги раскрываются дальше:

  • useState — Найденное на шагах 3-4 состояние объявляется именно через useState
  • Подъём состояния — Шаг про размещение состояния у общего родителя - это и есть lifting state up
  • События и обработчики — Шаг про обратный поток данных строится на колбэках, передаваемых вниз через props

Итог

  • Официальный метод 'Thinking in React' состоит из пяти шагов и превращает макет в работающий интерфейс предсказуемо
  • Шаг 1: разбить UI на дерево компонентов по принципу единственной ответственности - один компонент делает одно
  • Шаг 2: собрать статичную версию только на props, без всякого состояния и интерактивности
  • Шаг 3: найти минимальный набор состояния - данные, которые меняются и не выводятся из других данных
  • Шаг 4: определить, в каком компоненте состояние должно жить - в ближайшем общем родителе тех, кто его использует
  • Шаг 5: добавить обратный поток данных - колбэки вниз, чтобы дочерние компоненты могли менять состояние родителя

Связанные уроки

  • rc-03-components-props — Декомпозиция UI - это построение дерева компонентов, поэтому понимание компонентов и props обязательно
  • rc-06-usestate — Шаги про поиск состояния напрямую ведут к useState - инструменту, которым это состояние объявляют
  • rc-09-lifting-state — Определение, где должно жить состояние - это и есть подъём состояния к общему родителю
Мыслить на React: декомпозиция UI

0

1

Войти