Цель этой статьи — дать чистое и ясное представление о ngrx. Для этого я объясню, что нужно знать и понимать о ngrx, а затем мы увидим это в действии с простыми и понятными примерами кода.

Вот список тем, которые мы будем обсуждать в этой статье:

  • Что такое ngrx
  • Преимущества использования ngrx
  • Недостатки использования ngrx
  • Когда использовать ngrx
  • Действия, Редукторы, Селекторы, Хранилище и Эффекты

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

Что такое NGRX


NGRX — это группа библиотек, «вдохновленных» шаблоном Redux, который, в свою очередь, «вдохновлен» шаблоном Flux. Проще говоря, это означает, что шаблон Redux является упрощенной версией Flux шаблона, а NGRX — angular/rxjs версией Redux шаблона.

Что я имею в виду под «angular/rxjs» версией redux… «angular» часть заключается в том, что ngrx — это библиотека для использования в приложениях angular. Часть «rxjs» заключается в том, что реализация ngrx работает вокруг потока rxjs. Это означает, что он работает с использованием наблюдаемых и различных наблюдаемых операторов, предоставляемых «rxjs».

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


Давайте рассмотрим три принципа модели Redux и укажем на наиболее важные преимущества, которые они дают.

Единственный источник правды


В случае с архитектурой redux/ngrx это означает, что состояние всего вашего приложения хранится в дереве объектов в пределах одного хранилища.
В одном хранилище? О хранилищах мы поговорим позже, но для общего понимания, они несут ответственность за сохранение состояния и применение к нему изменений, когда им говорят об этом (когда отправляется действие, мы также поговорим о них позже).

Преимущества наличия одного источника правды многочисленны, но для меня наиболее интересным (потому что это то, что будет влиять на любое angular приложение) является следующее:

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

Состояние read-only (только для чтения)


Вы никогда не измените состояние напрямую, вместо этого вы будете отправлять действия, которые описывают действия с объектом (это могут быть такие вещи, как получение, добавление, удаление или обновление состояния).
Отправить действие?.. Мы поговорим о действиях позже, но для общего понимания, это идентификаторы операции над вашим приложением, и они могут быть запущены (или отправлены), чтобы сообщить приложению выполнить операцию, которую представляет действие.
Избегая обновлять состояние из разных мест и имея централизованное место для внесения изменений, которое реагирует на конкретные действия, вы получаете много преимуществ. Не говоря уже о самых важных:

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

Изменения вносятся с простыми функциями


Операция, инициируемая отправкой действия, будет простой функцией, называемой в рамках архитектуры redux, редукторами.

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

Состояние в redux приложении является неизменным! Поэтому, когда редуктор что-то меняет в состоянии, он возвращает новый объект состояния.

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

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

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

Отлично… Итак, каковы преимущества использования NGRX?


Мы уже упоминали большинство из них, когда говорили о принципах redux шаблона. Но давайте отметим наиболее важные преимущества использования redux шаблона в приложении (на мой взгляд):

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

… и минусы


  • У NGRX, конечно, есть кривая обучения. Она не большая, но и не такая уж и маленькая, и я думаю, что это требует некоторого опыта или глубокого понимания некоторых программных паттернов. Любой разработчик со средним стажем должен быть в порядке, но для младшего поначалу может быть немного запутанным.
  • Для меня это кажется немного многословным. Но каждый раз, когда вы добавляете какое-либо свойство в состояние, вам нужно добавлять действия, диспетчеры, вам может потребоваться обновить или добавить селекторы, эффекты, если таковые имеются, обновить магазин. А также вы запускаете конвейерную (конкатенацию) rxjs операторов и наблюдаемых повсюду.
  • NGRX не является частью угловых библиотек ядра и не поддерживается Google, по крайней мере, напрямую, потому что в команде Angular есть участники ngrx. Просто нужно кое-что обдумать, прежде чем вы добавляете библиотеку, которая будет большой зависимостью для вашего приложения.

Когда стоит использовать NGRX


Таким образом, по общему мнению, ngrx следует использовать в средних/больших проектах, когда управление состоянием начинает становиться сложным в обслуживании. Некоторые люди, более фанатичные, скажут что-то вроде «если у вас есть состояние, то у вас есть NGRX».

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

При этом я считаю, что сильная команда разработчиков Angular может также решить включить ngrx в решение, потому что они знают всю мощь redux шаблона, а также силу добавляемую операторами rxjs, и они чувствуют себя комфортно, работая с обоими…

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

NGRX Действия, Редукторы, Селекторы, Хранилище, и Эффекты


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



На изображении мы видим поток ngrx. Давайте объясню его…

  1. В наиболее распространенном сценарии все начинается с представления компонентов. Некоторые взаимодействия, осуществляемые пользователем, могут привести к тому, что компонент отправит действие.
    Действия…

    В объекте «Хранилище» имеется функция отправки (запуска) действий. Действия — это классы, реализующие интерфейс NGRX Action. У этих классов Action'ов есть два свойства (возьмем в качестве примера класс действия под названием GetUserName):

    type (тип): это строка только для чтения, описывающая, что означает действие. Например: '[User] Get User Login''.

    payload (полезная нагрузка): тип этого свойства зависит от того, какие данные нужно отправить редуктору. В случае предыдущего примера это будет строка, содержащая имя пользователя. Не все действия должны иметь полезную нагрузку.
  2. Если это действие не вызывает эффекта, редуктор будет анализировать это действие (обычно с помощью оператора switch) и возвращать новое состояние, которое будет результатом слияния старого состояния со значением, измененным вызовом этого действия.
    Редуктор...

    Редукторы — это простые функции, принимающие два аргумента: предыдущее состояние и Действие. При отправке Действие ngrx проходит через все редукторы, передающие в качестве аргументов предыдущее состояние и Действие, в том порядке, в котором редукторы были созданы, до тех пор, пока не найдет аргументы для этого действия.
  3. Если эффект запускается в результате отправки действия, то это происходит из-за того, что перед вызовом редуктора произойдут некоторые побочные эффекты. Вероятно, это может быть что-то вроде вызова службы HTTP для получения данных.
    Эффекты...

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

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

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

    В конце концов, редуктор будет выдавать еще одно действие, обычно относящееся к состоянию результата побочного эффекта (success, error и т.д.), затем редуктор войдет в сцену, о чем мы уже упоминали в потоке ngrx.
    После того, как эффект завершен (побочные эффекты закончены), новое действие «состояние-результат» выстреливает из эффекта (может быть, побочные эффекты успешны или неудачны).
  4. Теперь в магазине появилось новое состояние. Состоянием может быть большое дерево объектов, поэтому ngrx вводит селекторы, чтобы иметь возможность использовать только те фрагменты объекта, которые нам нужны в конкретном компоненте.
    Селекторы...

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

    Хранилище NGRX предоставляет нам функцию «выбрать» для получения частей нашего хранилища. Но что, если нам нужно применить некоторую логику к этому срезу, прежде чем использовать данные в компонентах.

    Здесь селекторы принимают меры. Они позволяют нам отделить любое преобразование данных среза состояния от компонентов. Функция выбора «store» принимает в качестве аргумента простую функцию, эта функция является нашим селектором.

    Хранилище ...

    Хранилище — это объект (экземпляр класса Store ngrx), который объединяет вещи, о которых мы упоминали ранее (действия, редукторы, селекторы). Например, когда отправляется действие (с использованием функции отправки объекта хранилища), хранилище является тем, которое находит и выполняет соответствующий редуктор.

    Он также является держателем состоянием приложения.


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