Эта статья вдохновлена ​​отличным докладом Майка Райана о Good Action Hygiene с NgRx на ng-conf 2018 и книгой под названием Thinking in Redux Автор: Нир Кауфман.



Вступление

Обычный способ создания типа действия - использовать источник действия или контекст действия, заключенный в квадратные скобки, за которыми следует имя действия. Это помогает познакомиться с потоком приложений на основе журналов действий в Store Devtools.

Я следую вышеупомянутому шаблону в своих приложениях Angular, но недавно я столкнулся с ситуацией, когда мне пришлось разрешить открытие модального окна уведомлений из разных областей приложения. Уведомление должно было отображаться в следующих ситуациях:

  • запрос пользователя о переходе к заблокированному упражнению,
  • ошибка возникает при загрузке / сохранении данных,
  • токен сеанса истек.

Сначала я просто создал часть ngrx / store, отвечающую за обработку уведомлений, и собирался использовать ее в различных областях приложения. К счастью, я наткнулся на доклад Майка Райана и понял, что это не будет идеальным решением, если я отправлю действие того же типа без учета источника действия. Другими словами, я бы все время использовал тип действия [Notification] Set или [Notification] Dispose, поэтому было бы невозможно ознакомиться с потоком приложения на основе в журналах действий. Просветление пришло, когда я наткнулся на книгу Нира Кауфмана и обнаружил создателей действий с контекстом. С помощью решения, представленного в книге, я смог убить двух зайцев одним выстрелом, а именно, что у меня была одна часть ngrx / store, отвечающая за обработку уведомлений из разных областей приложения, а также за отслеживание источника действия

Реализация

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

https://reusable-action-with-context.stackblitz.io/

Давайте исследуем важные части приложения.

Модели

Я создал интерфейс ActionWithContext, расширяющий интерфейс Action, чтобы обеспечить наличие свойства контекста.

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

Действия

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

Редукторы

Редуктор может сначала показаться немного странным с выражением true в качестве switch. Однако, если подумать, это имеет смысл, поскольку тип действия содержит контекст, который будет варьироваться в зависимости от источника действия, поэтому невозможно проверить однозначное соответствие внутри switch утверждение. Решение состоит в том, чтобы проверить, включает ли тип действия часть, независимую от контекста действия. Одним из недостатков этого подхода является то, что здесь не работает шаблон размеченного объединения, поэтому вам нужно использовать утверждение типа.

Эффекты

Поскольку некоторые уведомления следует удалять по прошествии определенного периода времени, необходимо прослушивать действие SetNotification. По той же причине, что и в предыдущем абзаце, вы не можете использовать оператор ofType для соответствия заданному типу действия. Идея состоит в том, чтобы использовать оператор filter и проверить, включает ли тип действия контекстно-независимую фразу.

Действия по отправке

Если вы имитируете настройку разных типов уведомлений, вы получите следующие журналы в Store Devtools:

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

Выводы

В статье я представил очень полезный шаблон для управления действиями ngrx / store, отправляемыми из разных областей приложения, без потери информации об источнике действия.

Примеры таких действий включают следующие сценарии:

  • обработка уведомлений,
  • рендеринг счетчик
  • императивное управление маршрутизацией.

И последнее, но не менее важное: я решил условно визуализировать компонент диалогового окна уведомлений рядом с основным выходом маршрутизатора вместо использования диалогового окна Angular Material, поскольку мне пришлось применять настраиваемую анимацию, когда диалоговое окно входит и выходит (в реальном приложении) .

Молись, люби, ненавидь, хлопай!