Angular IDPStrong Junior
🔥 0

Модуль 3 · урок 5 з 11

Сигнали і CD

Сигнали ти вже знаєш із модуля 2 як зручний спосіб тримати стан. Тут подивимось на них з іншого боку: як вони змінюють саму механіку перевірки й чому Angular рухається в цей бік.

Різниця в одному реченні

OnPush звужує перевірку до компонента: не змінився input — гілку пропускаємо. Сигнали звужують її до конкретного місця в шаблоні: змінився сигнал — оновлюється рівно той шматок розмітки, який його читав.

ONPUSH — ОДИНИЦЯ ПЕРЕВІРКИ Є КОМПОНЕНТ заголовок лічильник {{ total() }} таблиця на 1000 рядків підвал змінився input → звіряється весь шаблон СИГНАЛИ — ОДИНИЦЯ Є ВУЗОЛ ШАБЛОНУ заголовок лічильник {{ total() }} таблиця на 1000 рядків підвал змінився total → оновився один текстовий вузол Обидва підходи сумісні: сигнали всередині компонента з OnPush дають найточніше оновлення.
Сигнал знає своїх читачів поіменно, тому Angular не звіряє весь шаблон — він оновлює конкретні вузли.

Що це змінює в коді

// було: поле + ручне повідомлення
export class TaskList {
  tasks: Task[] = [];
  private cdr = inject(ChangeDetectorRef);

  load(): void {
    this.api.getTasks().subscribe(t => {
      this.tasks = t;
      this.cdr.markForCheck();
    });
  }
}

// стало: сигнал
export class TaskList {
  readonly tasks = signal<Task[]>([]);

  load(): void {
    this.api.getTasks().subscribe(t => this.tasks.set(t));
  }
}

Зникає не лише рядок із markForCheck, а цілий клас помилок: «я оновив дані, а екран не змінився». Angular дізнається про зміну від самого сигналу.

Сигнальні inputs і OnPush

export class TaskCard {
  task = input.required<Task>();
  readonly isLate = computed(() => new Date(this.task().dueDate) < new Date());
}

Тут computed робить те, для чого раніше писали ngOnChanges: перераховується сам, коли прийшов новий task. І, що важливо, лише коли прийшов новий — а не на кожній перевірці, як було б із методом у шаблоні.

Правило про незмінність нікуди не зникло

const tasks = signal<Task[]>([]);

tasks().push(item);                        // ❌ те саме посилання → нічого не станеться
tasks.update(list => [...list, item]);     // ✅

Сигнал порівнює значення так само, як Angular порівнює input: за посиланням. Тому попередній урок актуальний і для сигнального стилю. Якщо треба інша логіка порівняння — її можна задати явно:

const user = signal(initial, { equal: (a, b) => a.id === b.id });

Куди все рухається

Zoneless-режим із модуля 3, уроку 1, працює саме на сигналах: без zone.js Angular не має іншого способу дізнатись про зміну, крім явного повідомлення. Тобто сигнали — це не просто зручний синтаксис, а фундамент, на якому будується наступне покоління change detection.

Практичні висновки
  • Стан компонента тримай у сигналах, не в звичайних полях.
  • Похідні значення — computed, а не методи в шаблоні.
  • OnPush усе одно став: він відсікає гілки цілком.
  • Оновлюй незмінно, навіть із сигналами.
Чого не робити
  • Не змішувати: половина стану в сигналах, половина в полях.
  • Не читати сигнал у effect, щоб «оновити» інший сигнал.
  • Не залишати ручні підписки там, де достатньо toSignal (модуль 4).
  • Не вважати, що сигнал звільняє від track у @for.

≈ 35 хв · +25 XP за урок