Angular: пример использования NGRX

image
Эта статья является продолжением поста «Angular: понятное введение в NGRX»

Пример NGRX



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

План действий:

  1. Установка библиотеки
  2. Создание структуры папок для хранилища
  3. Создание хранилища и начальных значений
  4. Создание действий (Actions)
  5. Создание редукторов (Reducers)
  6. Создание эффектов (Effects)
  7. Создание селекторов (Selectors)
  8. Конечная настройка
  9. Использование хранилища в компонентах

Итак, давайте сделаем это…

Установка библиотеки


Мы собираемся использовать Angle Cli для создания проекта, а затем мы добавим библиотеки ngrx.

Создадим проект:

ng new angular-ngrx --style=scss

Добавим необходимые библиотеки NGRX:

npm install @ngrx/core @ngrx/store @ngrx/effects @ngrx/store-devtools @ngrx/router-store --save


Мы устанавливаем почти все библиотеки экосистемы ngrx. Большинство из них достаточно ясно описывают их назначение: ядро, хранилище, эффекты, но есть пара, для которой вы можете задаться вопросом, для чего они нужны?

  • store-devtools — Мощный инструмент для отладки.
  • router-store — Сохраняет состояние углового роутера в хранилище.


Структура попок для хранилища


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

image

Структура папок является представлением фактической композиции хранилища. У вас будет основная папка с названием «store» и пять подпапок, которые представляют каждого из ключевых игроков магазина: «Actions», «Effects», «Redurs», «Selectors» и «State».

Создание хранилища и начальных значений


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

Мы создали два интерфейса для определения пользователя и конфигурации. У нас также есть один для ответа HTTP пользователя, это просто массив IUser.

image

image

Начнем с состояния пользователя (store/state/user.state.ts):

image

Что мы здесь делаем:
  1. Мы создаем и экспортируем интерфейс со структурой пользовательской среды.
  2. Мы делаем то же самое с начальным пользовательским состоянием, которое реализует недавно созданный интерфейс.

Для состояния конфигурации мы делаем то же самое (store/states/config.state.ts):

image

Наконец, нам нужно сгенерировать состояние приложения (store/states/app.state.ts):

image

  1. Состояние приложения содержит состояние пользователя и конфигурации, а также состояние маршрутизатора.
  2. Потом задаем начальное состояние приложения.
  3. Наконец, экспортирует функцию, чтобы получить начальное состояние (мы будем использовать его позже).


Создание Действий.


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

Нам нужно создать действия для пользователей и настройки. Начнем с действий пользователя (store / actions / user.actions.ts):

image

Давайте немного пройдемся по коду:

  1. Мы экспортируем Enum, содержащий определение для типов действий. Таким образом, мы избегаем использования и повторения строк для использования типов действий, процесс, который может легко порождаться ошибками.
  2. Потом мы создаем и экспортируем класс для каждого из ваших действий. Все они должны реализовать интерфейс Action из ngrx. Наконец, мы устанавливаем тип в одно из значений перечислений, и если вам нужно полезное содержимое для действия, вы добавляете его в конструктор класса.
  3. Наконец, мы экспортируем тип, содержащий наши классы действий. Это обеспечит нам проверку типов, которую мы можем использовать, например, в наших редукторах.

И это все… создавать действия просто. Давайте посмотрим, как выглядят действия конфигурации (store/actions/config.actions.ts):

image

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

Отлично, мы уже определили состояние и действия… давайте создадим редукторы!

Создание Редукторов


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


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

Нам понадобится редуктор для пользователей и другой для конфигурации, но нам также понадобится генерировать редукторы приложений, давайте начнем с рассмотрения редукторов пользователей (store/redurs/user.reducers.ts):

image

Давайте обсудим реализацию:
  1. Объявление редуктора получает состояние и, в этом случае, действия пользователя и возвращает IUserState.
  2. Используя оператор switch, мы генерируем наблюдения для каждого возможного типа действия.
  3. Каждый случай возвращает новый объект, который является результатом слияния старого состояния и нового значения.
  4. Все редукторы имеют результат по умолчанию, который просто возвращает состояние без каких-либо изменений.


И это все. Вы не найдете ничего другого в редукторе. Давайте взглянем на редукторы конфигурации (state/redurs/config.reducers.ts):

image

Наконец, давайте посмотрим на редукторы приложений (store):

image

Здесь мы добавляем все редукторы на карту редукторов действий приложения. Мы используем карту редуктора действий для дополнительной проверки типов. Позже мы собираемся предоставить это приложение редукторы для модуля store.

Добавим Эффекты


Обязательно прочтите определение «Эффекты», которое мы обсуждали в предыдущей статье.


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

Начнем с пользовательских эффектов (store/effects/user.effects.ts):

image

Много что происходит в этом файле. Давайте попробуем объяснить их:
  1. Мы объявляем наши пользовательские эффекты с помощью инъекционного декоратора.
  2. Мы объявляем наши эффекты, используя декоратор эффектов, предоставленный ngrx/Effects.
  3. Используя действия, предоставленные ngrx / Effects, мы собираемся запустить конвейер нашего оператора для этого эффекта.
  4. Следующим шагом является установка типа действия эффекта с помощью оператора ofType.
  5. Следующие части представляют собой операторы rxjs, которые мы используем для получения того, что нам нужно (у нас уже есть ссылка на документацию по rxjs в этой статье).
  6. Наконец, в последнем операторе Effect отправит еще одно действие.
  7. В конструкторе мы внедряем сервисы, которые мы собираемся использовать, действия для ngrx / Effects, и в этом случае также хранилище (учтите, что это демо, и мы получаем выбранного пользователя из списка пользователей в наше хранилище).


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

Рассмотрим эффекты конфигурации (store/effects/config.effects.ts):

image

Теперь пришло время поговорить о селекторах…

Создание Селекторов


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


Нет смысла повторять выборки срезов нашего состояния повсеместно, поэтому давайте создадим некоторые селекторы, которые мы можем использовать повторно.

Как всегда, давайте сначала посмотрим на пользовательские селекторы (store/selectors/user.selectors.ts):

image

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

Первый параметр — это фрагмент хранилища, которое будет использоваться для получения данных (это может быть массив с несколькими частями состояния), второй параметр — анонимная функция, которая будет решать, что будет возвращать селектор.

Давайте посмотрим на конфигурационные селекторы (store/selectors/config.selectors.ts):

image

Итоговая настройка


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

Давайте дополним модуль приложения:

image

Что мы здесь сделали:

  1. Мы импортируем наши редукторы и предоставляем их в forRoot модуля хранилища.
  2. Мы импортируем наши эффекты и предоставляем их внутри массива в модуль forRoot эффектов.
  3. Мы устанавливаем конфигурацию для модуля состояния маршрутизатора, предоставляющего маршрутизатор stateKey.
  4. И мы добавляем инструменты разработчика магазина, если среда не является производственной.

Первые два шага необходимы, в то время как шаги 3 и 4 я настоятельно рекомендую, но они не являются обязательными.

Теперь мы наконец сделали… мы можем использовать наше хранилище в компонентах!

Использование хранилища в некоторых компонентах



Мы приближаемся к концу! Давайте посмотрим, как использовать наше хранилище…

Во-первых, давайте получим конфигурацию при запуске приложения:

image

  1. Мы добавляем хранилище в наш app.component.
  2. Мы устанавливаем для свойства компонента значение селектора в конфигурации, потому что хотим отобразить часть этой информации в HTML.
  3. В onInit мы отправляем действие, чтобы получить конфигурацию.


Вот и все… Мы уже кодируем эффект, который будет управлять этим действием, и редуктор, который будет обрабатывать этот эффект. Как только Хранилище перейдет в новое состояние, селектор изменит значение нашего свойства.

Как это связывать с HTML:

image

Как только у config$ будет значение, мы увидим его в HTML.

Теперь посмотрим список пользователей (containers/users/users.component.ts):

image

  1. Подобно тому, как мы управляем конфигурацией, мы собираемся получить список пользователей. Сначала мы внедряем хранилище в компонент пользователя.
  2. На onInit мы отправляем действие, чтобы получить пользователей.
  3. Мы создаем свойство для компонента и присваиваем ему список пользователей, используя селектор списка пользователей.


HTML выглядит так:

image

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

Давайте посмотрим на компонент пользовательского контейнера:

image

Этот компонент получает идентификатор параметра из активированного маршрута, а с остальным вы, вероятно, уже знакомы, отправляет идентификатор в качестве параметра, выбирает выбранного пользователя…

Если вы отлаживаете приложение, вы можете увидеть инструменты разработчика, которые довольно просты в использовании… но в этой статье мы изучили достаточно, и я надеюсь, что вы без труда разберетесь с этими инструментами.

Заключение



В этой статье я попытался представить ясное и понятное введение в NGRX, предоставив вам все, что вам нужно знать, чтобы начать разработку используя этот инструмент.

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