Как получить все преимущества MobX, не «загрязняя» ваши магазины и компоненты

В этом посте показано еще одно путешествие, которое я совершил при разработке timefic.com, от компонентов React с явным MobX внутри компонентов и хранилищ к компонентам и хранилищам React, где нет единой ссылки на MobX вообще , но все же используйте MobX под капотом.

Примечание: это вторая часть этой статьи.

В предыдущей статье я рассказал вам о преимуществах определения одного hoc (компонента более высокого порядка) для всего вашего приложения. Этот компонент на самом деле не является компонентом React, а является функцией, возвращающей расширенный компонент.

Я предлагаю вам сделать каждый компонент вашего приложения расширенным. Итак, если в вашем приложении 250 компонентов, вам нужно улучшить 250 компонентов:

Вы перестанете думать о:

  • Как данные и функции входят в свойства вашего компонента.
  • Если компонент выполняет повторную визуализацию, предположим, что не нужно.
  • И перестаньте нуждаться в классах для методов жизненного цикла.

Ваш компонент больше не несет ответственности за эти «мелкие детали»: главный ответственен!

Итак, сцена 1 была стандартным подходом (с использованием MobX внутри ваших компонентов и ваших магазинов), а сцена 2 не использовала явный MobX, помните? Вернемся к истории 👇

Сцена 2: подход «Независимость от MobX»

Вкратце: идея состоит в том, чтобы использовать MobX, но без ссылки на него.

Уровень магазина

На уровне магазина использование MobX «как обычно» доставляло мне некоторые неудобства, потому что:

  • Каждый из моих магазинов (17 в случае модуля "Встречи") становился все больше и больше. Итак, я создал функцию для каждого поля в отдельном файле, чтобы преобразовать хранилище больше как индексный файл.
  • Слово это было повсюду. Мне нужно передать любое вычисленное значение нужным им вводом, поскольку теперь они были в отдельном файле.
  • У меня не было механизма внедрения зависимостей, поэтому тестировать хранилище было сложно (и все декораторы тоже не помогают).

Как вы видите на изображении, в этом ActionsStore есть 1 наблюдаемое и 4 вычисляемых поля. Каждое вычисляемое поле - это функция, которая принимает входные данные из самого магазина и других магазинов, в данном случае: PeopleStore, MeetingsStore, MembersStore и Государство.

Для тестирования этого файла мне потребовались данные в упомянутых хранилищах, но как я могу поместить данные в них?

Магазин, который вы просматриваете, является одним из моих простых магазинов, поэтому представьте себе файл, обычно состоящий из 200 строк, если вы хотите найти что-то, что не работает хорошо… 😧

Итак, мне нужно было что-то с этим делать.

Я не помню точно, как именно (я всегда читаю некоторые методы функционального программирования), но возникла каррированная функция, указывающая путь.

Как показано на изображении, каррированной версии не требуется, чтобы this и хранилище State находились в области действия функции. Теперь self определяет эту область действия (область действия - это само хранилище, как мы увидим). Здесь есть вся информация, которая может понадобиться каждому полю в магазине (другие магазины и другие поля в том же магазине).

Итак, поскольку функция каррирована, если вы вызовете getMeetingActions (this), вы получите функцию, которая имеет именно те данные, которые им необходимы для вычисления значения.

Возникает стратегия:

Каждое вычисленное поле будет получено путем вызова функции (каррированной функции) с самим хранилищем (this) в качестве контекста.

Но мы скроем эту деталь реализации, чтобы магазины выглядели так:

Посмотрите на изображение: где MobX?

Подумайте об этом: если каждое вычисленное значение имеет одинаковую сигнатуру, в данном случае это результат вызова функции с аргументом this, то их можно определить как список полей внутри объекта, как показано на рисунке.

Нечто подобное используется для действий, наблюдаемых и реакций: основного строительного блока большинства магазинов MobX.

Например, вычисленные значения реализуются следующим образом:

Более того, если вы хотите использовать другую библиотеку реактивного состояния, подобную MobX, вам просто нужно прикоснуться к этому фрагменту кода!

Преимущества:

  • Создание стандартного магазина: сохраняет объект, созданный с помощью (фабричной) функции. Нужно сделать каждый магазин отлаживаемым? Просто добавьте window [StoreName] = this к этой фабричной функции. Теперь вы можете проверить любой магазин, созданный в консоль (это очень полезно).
  • Уменьшенный шаблон: сравните магазин до и после. Последний не только меньше, но и имеет 8 вычисляемых полей вместо 4.
  • Разборчивость: тоже неприятно читать?
  • Независимый от фреймворка: устали от MobX (мне он нравится!)? Просто реализуйте его примитивы другим способом, и вы готовы к работе!
  • Возможность тестирования: вы будете тестировать функцию, которая возвращается из каррированной функции, что означает, что все его зависимости уже переданы в качестве аргументов. Кроме того, вы можете создать новый набор тестов согласованности, беря объект внутри createStoreDefinition и сравнивая его с тем, что фактически используется вне магазина (компоненты или другие хранилища). Это может быть сам пост в будущем, но имейте в виду, что определение можно использовать не только для «генерации кода», но и для его тестирования.

Для комплектации магазина не хватает только одной детали:

Каждое хранилище должно знать минимальный набор других хранилищ, потому что внутри this должна быть ссылка на контекст, который нужен вычисляемым полям.

Другими словами:

  • Если для myMeetingActions требуется значение State ['App_meeting_id'], тогда State необходимо использовать для создания ActionsStore.

Это означает, что циклических зависимостей быть не может.

Если для магазина C нужны Store A и Store B, тогда Store B не может зависеть от Store C. В случае, если это произойдет (это произойдет), вам нужно сломать Магазин C, например, в двух магазинах. Это имеет смысл, когда вы вынуждены это делать, потому что понимаете, что есть чередование вещей (плохо спроектированных).

Например, вот список магазинов в timefic:

Последнее преимущество?

Глядя на эти файлы, действительно легко понять, как собираются данные.

Вот и все. Надеюсь, это имеет смысл и может быть полезно!