State Management

MobX: архитектура

В приложении растёт состояние: пользователь, корзина, каталог, уведомления. Свалить всё в один гигантский стор означает потерять границы предметных областей. Разнести по несвязанным глобальным переменным означает потерять способ дотянуться от корзины до текущего пользователя. MobX предлагает архитектурный ответ из мира OOP: каждая предметная область это отдельный стор-класс, а корневой root store держит их вместе и раздаёт ссылки друг на друга.

  • Доменные модели интернет-магазина: UserStore, CartStore, CatalogStore под одним root store
  • Финансовые и учётные приложения с богатой бизнес-логикой в классах сущностей
  • Редакторы и CRM, где сущности связаны ссылками и методами друг на друга
  • Команды с бэкграундом в OOP, которым ближе классы и инкапсуляция, чем редьюсеры
  • Проекты, где сериализация и снимки состояния важны и берут MobX-State-Tree

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

  • observable, computed и action как строительные блоки стора
  • Идея инкапсуляции: данные и поведение в одном классе
  • Понимание, зачем нужен единый доступ к разным частям состояния
  • MobX: observable, computed, action

Доменные сторы и root store

Базовый приём архитектуры на MobX это деление состояния по предметным областям. Каждая область получает свой стор-класс: UserStore, CartStore, CatalogStore. Внутри стора живут только данные и логика своей области. Это прямое следование принципу единственной ответственности: стор корзины не знает деталей каталога, а лишь обращается к нему через ссылку.

Чтобы доменные сторы могли дотягиваться друг до друга, их собирают под корневым root store. RootStore создаёт каждый доменный стор и передаёт ему ссылку на себя. Через эту ссылку любой стор находит соседей: стор корзины через root доходит до текущего пользователя, чтобы посчитать скидку.

Ссылка root исключается из наблюдения через { root: false }, потому что сам root store не должен быть observable-значением: это контейнер, а не данные. Наблюдаемыми остаются поля доменных сторов, а root лишь даёт навигацию между ними.

В React один экземпляр root store обычно прокидывают через Context, а компоненты достают нужный доменный стор хуком. Так root остаётся единой точкой сборки, а компоненты подписываются на конкретные доменные сторы, а не на весь граф состояния сразу.

Зачем доменные сторы собирают под корневым root store?

OOP-стиль и богатые предметные модели

Сила MobX раскрывается, когда предметная область богата поведением, а не только данными. Сущность вроде заказа или проекта это класс: поля хранят состояние, computed выводят производные характеристики, методы-action меняют состояние по правилам домена. Логика живёт рядом с данными, которыми управляет, а не разнесена по редьюсерам и селекторам.

Здесь домен говорит сам за себя. total и canPlace это computed: они выводятся из строк и статуса и пересчитываются сами. Метод place меняет статус только если canPlace, и правило перехода инкапсулировано в классе. Компонент не дублирует эту логику: он читает canPlace и вызывает place, а корректность держит модель.

  • Логика размазана по UI — Условие можно ли разместить заказ проверяется в компоненте. То же правило копируется в нескольких местах и рассинхронизируется
  • Логика в доменной модели — canPlace и place живут в классе Order. Одно место истины для правила, компоненты лишь читают и вызывают

Именно за это MobX ценят команды с OOP-бэкграундом: предметная модель выражается классами с инкапсуляцией и поведением, как в типичном backend-домене. Реактивность добавляется одним вызовом в конструкторе и не размывает структуру модели на action-creator и reducer.

В чём выгода держать правило can ли разместить заказ как computed canPlace внутри класса Order, а не проверять его в компоненте?

MobX-State-Tree и где MobX силён

Поверх MobX существует надстройка MobX-State-Tree, сокращённо MST. Она описывает состояние не свободными классами, а типизированными узлами дерева: у каждой модели объявлен тип полей, есть представления (аналог computed) и действия. За счёт строгой структуры MST даёт из коробки снимки состояния, сериализацию в JSON и обратно, патчи изменений и middleware. Это полезно там, где состояние нужно сохранять, восстанавливать и отслеживать по шагам.

MST берут, когда важны снимки и сериализация: сохранить всё дерево состояния, восстановить его, проиграть изменения. Чистый MobX берут, когда нужна свобода классов и не нужна жёсткая типизация узлов. Граница выбора между ними проходит по тому, насколько важны структурные возможности дерева против гибкости обычного OOP.

Где MobX силёнГде MobX слабее
Богатые предметные модели со связями и поведениемПростое плоское UI-состояние: одна модалка, тема
OOP-домены, близкие к backend-сущностямКоманды без OOP-бэкграунда, которым ближе атомы
Автоматическое отслеживание сложного графа зависимостейСценарии, где важна явная иммутабельность и time-travel
Сериализация и снимки через MSTМинимальный бандл, где важнее лёгкий стор

Честная граница: для простого клиентского состояния вроде открытой панели или выбранной темы тяжесть классов и root store избыточна, и лёгкий стор вроде Zustand часто читается проще. MobX окупается там, где предметная модель богата поведением и связями, а не там, где состояние это пара флагов.

В каком сценарии архитектура на доменных сторах MobX окупается сильнее всего?

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

Этот урок про архитектуру состояния на MobX. Рядом стоят соседи:

  • MobX: observable, computed, action — Доменные сторы это классы на observable, computed и action из базового урока
  • MobX: reactions — Реакции мостят доменные сторы с персистентностью, логами и синхронизацией

Итог

  • Состояние делят на доменные сторы: по стор-классу на предметную область (пользователь, корзина, каталог)
  • Корневой root store держит доменные сторы вместе и раздаёт им ссылки друг на друга
  • OOP-стиль: данные это поля, производные это computed, изменения это методы-action внутри класса
  • Связи между сторами идут через ссылку на root store, а не через глобальные переменные
  • MobX-State-Tree (MST) надстройка с явными типами узлов, снимками и сериализацией из коробки
  • MobX силён на богатых предметных моделях со связями и поведением, слабее на простом плоском UI-состоянии

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

  • sm-22-mobx-observables — Доменные сторы строятся на observable, computed и action из базового урока MobX
  • sm-23-mobx-reactions — Реакции связывают доменные сторы с эффектами вроде персистентности и синхронизации
MobX: архитектура

0

1

Войти