Найти тему
Nuances of programming

Плохие практики Angular

Оглавление

Источник: Nuances of Programming

Загрязнение ngOnInit

ngOnInit — один из самых важных хуков жизненного цикла в компонентах Angular. Он используется для инициализации данных, настройки слушателей, создания соединений и т.д. Однако в некоторых случаях он перегружает хук жизненного цикла:

Рассмотрим этот компонент. У него есть всего два жизненных цикла. Однако метод ngOnInit выглядит ужасно. Он подписывается на различные события изменения формы, потоки fromEvent, а также загружает много данных. Он состоит из 40 строк кода, а если включить опущенное здесь содержимое обратных вызовов subscribe, то мы получим более 100 строк, что противоречит даже самым мягким рекомендациям. Чтобы добраться до других методов, помимо ngOnInit придется прокручивать весь этот беспорядочный кусок кода (или закрывать/открывать его при необходимости). Более того, из-за большого количества смешанных концепций и задач усложняется поиск элементов внутри самого метода ngOnInit.

Теперь рассмотрим исправленную версию того же компонента:

Логика компонента сохраняется, меняется лишь способ организации кода. Теперь метод ngOnInit вызывает три различных метода для загрузки начальных данных из сервисов, установки прослушивателей изменения формы и прослушивателей событий DOM (при необходимости). Эти изменения упрощают чтение компонента с первого раза (прочтите ngOnInit — разберитесь, с чего он начинается, и если вам нужны подробности реализации, просмотрите соответствующие методы). Поиск источника ошибок также упрощается: если прослушиватели форм работают неправильно, перейдите в setupFormListeners и т.д.

Не загрязняйте метод ngOnInit — разделите его на несколько частей!

Написание бесполезных селекторов директив

Директивы Angular — мощный инструмент, позволяющий применять пользовательскую логику к различным элементам HTML. При этом также используются селекторы CSS, которые предоставляют еще больше возможностей. Для примера возьмем директиву ErrorHighlightDirective, которая проверяет наличие ошибок в formControl соответствующего элемента и применяет к нему определенный стиль. Допустим, мы добавляем в нее селектор атрибута [errorHighlight]. Она работает хорошо, однако теперь необходимо найти все элементы формы с атрибутом formControl и добавить в них [errorHighlight]. Утомительная задача. Мы можем использовать селектор атрибута директивы [formControl]. Директива выглядит следующим образом:

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

Но на этом использование не заканчивается. Допустим, мы хотим применить анимацию тряски ко всем formControls, в которых есть класс has-error. Мы можем с легкостью написать директиву и привязать ее с помощью селектора класса: .has-error.

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

Логика внутри конструктора сервиса

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

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

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

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

Добавление нового состояния

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

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

… можно преобразовать в этот:

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

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

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

Заключение

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

Читайте также:

Читайте нас в телеграмме и vk

Перевод статьи Armen Vardanyan: Angular Bad Practices: Revisited