Angular прошел долгий путь с тех пор, как я начал использовать его еще в 2013 году. Дни «$ scope» и массивных представлений / контроллеров были заменены архитектурами на основе компонентов и более элегантными шаблонами. Один из самых популярных паттернов за последний год или около того - NgRx. На каждого сторонника NgRx, похоже, есть один полностью не согласный, а другой - все равно. Я слышу много разговоров о том, действительно ли проекту нужен NgRx, и скажу, что если вы не уверены, то, вероятно, он вам не нужен.

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

Одно из альтернативных решений, которое немного обсуждают, - это обслуживание с темой, но после поиска в Интернете может быть сложно найти хорошие примеры того, как его реализовать. Первый вопрос, который приходит в голову: «Если это такое хорошее решение, почему о нем не говорят больше людей»? Я сам задал этот вопрос и начал копаться, чтобы понять, о чем идет речь.

Служба с субъектом - это простой шаблон, который при правильном применении дает разработчикам четкий путь к обновлению до NgRx (или аналогичного шаблона redux) практически без необходимости рефакторинга. Основная предпосылка заключается в том, что каждая служба имеет общедоступный объект поведения, который будет установлен на наблюдаемый поток, возвращаемый нашими вызовами службы.

Самым большим изменением здесь является то, что когда вы вызываете службу пользователя getAll function, вы больше не получаете ссылку на наблюдаемое, возвращаемое http-вызовом. Вместо этого субъект поведения (наблюдаемый поток) получает новую ценность, добавленную к потоку. Это позволяет нескольким компонентам совместно использовать одни и те же данные и не беспокоиться о том, как данные обновляются. Мы защищаем объект поведения, делая его закрытым и предоставляя свойство только для чтения, которое возвращает только наблюдаемый поток и не позволяет другим напрямую вмешиваться в поток.

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

Итак, теперь, когда вы понимаете основную предпосылку того, что такое сервис с предметом, мы готовы посмотреть, как все это будет реализовано.

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

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

Компонент контейнера будет отвечать за вызов пользовательской службы для получения данных. В приведенном ниже примере переменная «user $» представляет собой наблюдаемый поток пользовательских объектов, который установлен для нашего субъекта поведения службы пользователя. Каждый раз, когда субъект поведения получает новое значение, компонент контейнера также получит это значение без необходимости уведомления. При инициализации компонента контейнера вызывается метод «getAll» пользовательской службы, и после завершения вызова субъект поведения получит новое значение.

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

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

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

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

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