Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Сигналы: signal, computed, effect

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

Создание и чтение

Функция signal() создаёт сигнал с начальным значением. Чтобы прочитать значение, сигнал вызывают как функцию:

// src/app/todo-list/todo-list.ts
import { Component, signal } from '@angular/core';
 
@Component({
  selector: 'app-todo-list',
  templateUrl: './todo-list.html',
})
export class TodoList {
  count = signal(0);
}
<!-- src/app/todo-list/todo-list.html -->
<p>Задач: {{ count() }}</p>

На странице: «Задач: 0». Скобки после имени обязательны — и в шаблоне, и в классе.

Изменение: set и update

set() записывает новое значение, update() вычисляет его из старого:

// src/app/todo-list/todo-list.ts
export class TodoList {
  count = signal(0);
 
  increment() {
    this.count.update((n) => n + 1);
  }
 
  reset() {
    this.count.set(0);
  }
}
<!-- src/app/todo-list/todo-list.html -->
<p>Задач: {{ count() }}</p>
<button (click)="increment()">+1</button>
<button (click)="reset()">Сбросить</button>

Каждый щелчок по «+1» увеличивает число на странице, «Сбросить» возвращает ноль.

Сигнал с массивом

Для списка дел сигнал хранит массив объектов. Опишите тип задачи в отдельном файле src/app/todo.ts:

// src/app/todo.ts
export interface Todo {
  id: number;
  title: string;
  done: boolean;
}
// src/app/todo-list/todo-list.ts
import { Component, signal } from '@angular/core';
import { Todo } from '../todo';
 
@Component({
  selector: 'app-todo-list',
  templateUrl: './todo-list.html',
})
export class TodoList {
  todos = signal<Todo[]>([
    { id: 1, title: 'Купить хлеб', done: true },
    { id: 2, title: 'Позвонить Олегу', done: false },
  ]);
 
  private nextId = 3;
 
  add(title: string) {
    const todo = { id: this.nextId++, title, done: false };
    this.todos.update((list) => [...list, todo]);
  }
}

update() возвращает новый массив через spread — так Angular видит, что значение изменилось.

computed

computed() создаёт сигнал только для чтения, который вычисляется из других сигналов и пересчитывается сам:

// src/app/todo-list/todo-list.ts
import { computed } from '@angular/core';
 
export class TodoList {
  // ...todos и add() как выше
  left = computed(() => this.todos().filter((t) => !t.done).length);
}
<!-- src/app/todo-list/todo-list.html -->
<p>Осталось сделать: {{ left() }}</p>

Выводится «Осталось сделать: 1». После добавления задачи число увеличится без единой строки кода для обновления.

effect

effect() выполняет действие каждый раз, когда меняются прочитанные в нём сигналы. Его создают в конструкторе или при объявлении поля:

// src/app/todo-list/todo-list.ts
import { effect } from '@angular/core';
 
export class TodoList {
  // ...todos как выше
  constructor() {
    effect(() => {
      localStorage.setItem('todos', JSON.stringify(this.todos()));
    });
  }
}

Список сохраняется в localStorage при каждом изменении. Эффекты нужны для связи с внешним миром; значения для показа вычисляйте через computed.

Частая ошибка

Изменять массив внутри сигнала напрямую: this.todos().push(task). Ссылка на массив осталась прежней, поэтому сигнал не узнаёт об изменении, и computed не пересчитается. Всегда создавайте новый массив через update() и spread.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.