Современный Angular: Заменяем жизненные циклы на сигналы
- пятница, 29 мая 2026 г. в 00:00:11
Если вы пишете на Angular, то наверняка часто используете хуки жизненного цикла вроде ngOnChanges, ngOnInit и ngOnDestroy. С появлением сигналов и концепции Zoneless (когда Zone.js уже не обязателен) у нас появились более элегантные и читаемые альтернативы.
Давайте разберем, как современный подход позволяет упростить код и избавиться от "шумных" методов жизненного цикла.
Было: классический подход с ngOnChanges
@Component({...}) export class PricingComponent implements OnChanges { @Input() price = 0; totalPrice = 0; constructor(private taxService: TaxService) {} ngOnChanges(changes: SimpleChanges) { if (changes['price']) { // При обновлении инпута дергаем сервис this.totalPrice = this.taxService.calculateTotal(this.price); } } }
Стало: реактивно с сигналами
@Component({...}) export class PricingComponent { // Сигнальный вход price = input<number>(0); private taxService = inject(TaxService); // Реактивно вычисляем общую цену при каждом изменении price totalPrice = computed(() => this.taxService.calculateTotal(this.price())); }
Плюсы: короче, читабельно, более производительно (вычисляется только когда реально нужно).
ngOnInit часто использовали как "безопасную" точку, где входные параметры уже гарантированно доступны. С сигналами мы можем инициализировать данные прямо на уровне свойств, реактивно.
Было: инициализация в ngOnInit
@Component({...}) export class UserComponent implements OnInit { @Input() userId!: string; userData!: User; constructor(private userService: UserService) {} ngOnInit() { // Ждем, пока Angular установит userId this.userData = this.userService.getUserSync(this.userId); } }
Стало: сигнальный подход
@Component({...}) export class UserComponent { userId = input.required<string>(); // обязательный вход private userService = inject(UserService); // Данные пользователя вычисляются реактивно при каждом изменении userId userData = computed(() => this.userService.getUserSync(this.userId())); }
Дополнительный бонус: теперь при изменении
userId(если такое возможно) данные обновятся автоматически — без лишних телодвижений.
Больше не нужно вручную хранить массивы подписок (Subscription[]) и отписываться в ngOnDestroy. Спасибо оператору takeUntilDestroyed().
Было: ручное управление подпиской
@Component({...}) export class AlertComponent implements OnDestroy { private sub: Subscription; constructor(private alertService: AlertService) { this.sub = this.alertService.alerts$ .subscribe(alert => console.log(alert)); } ngOnDestroy() { this.sub.unsubscribe(); } }
Стало: автоматическая отписка через pipe
@Component({...}) export class AlertComponent { constructor(private alertService: AlertService) { this.alertService.alerts$ .pipe(takeUntilDestroyed()) // Angular сам отпишет при уничтожении компонента .subscribe(alert => console.log(alert)); } }
Код стал лаконичнее, и риск забыть про unsubscribe исчезает.(А если совсем перейти с RxJS на сигналы, то можно сделать еще проще — но это уже тема для отдельной статьи.)
Как видите, большинство повседневных задач, где раньше нужны были хуки, теперь решаются через сигналы и computed. Код получается более декларативным, менее связанным с временем жизни компонента и легче для тестирования.
Означает ли это, что жизненные циклы полностью уходят в прошлое? Нет. Они остаются для специфических задач — например, ngAfterViewInit всё ещё незаменим, когда нужна прямая работа с DOM или canvas.
Но как инструмент "на каждый день" — да, хуки успешно заменяются современными реактивными примитивами.
Переход на сигналы — это действительно эволюция или просто ещё один "очередной способ писать то же самое"? Сталкивались ли вы с подводными камнями при миграции с жизненных циклов на computed и takeUntilDestroyed?
Особенно интересно услышать мнение тех, кто уже пробовал Zoneless-подход в боевых проектах:
Какие грабли успели собрать?
В каких кейсах без старых хуков всё-таки не обойтись?
Как оцениваете производительность после перехода?
А если есть чем поделиться или возразить — добро пожаловать в комментарии. Живое обсуждение — лучший способ разобраться в новой парадигме.