Когда будет выполняться функция эффекта для угловых сигналов?

Почему эти две функции #workingUpdate и #brokenUpdate ведут себя по-разному? На самом деле я ожидал бы, что обе функции завершатся неудачно, поскольку ElementRef не существует во время вызова конструктора.

      @Component({
  selector: 'test-app',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule],
  template: `
  <button (click)="addOne()">count+</button><br/>
  count: {{count()}}<br/>
  output1: <span #output1></span><br/>
  output2: <span #output2></span><br/>
  `,
})
export class App {
  count = signal(0);

  @ViewChild('output1') output1!: ElementRef;
  @ViewChild('output2') output2!: ElementRef;

  #workingUpdate = () => {
    const c = this.count();
    this.output1.nativeElement.innerHTML = c;
  };
  #brokenUpdate = () => {
    this.output2.nativeElement.innerHTML = this.count();
  };

  constructor() {
    effect(this.#workingUpdate);
    effect(this.#brokenUpdate);
  }

  addOne() {
    this.count.update((c) => c + 1);
  }
}

Я создал простой пример . Первоначально я столкнулся с этой проблемой при вызове интерфейса обновления стороннего компонента. Я использую структуру #workingUpdate, чтобы решить свою проблему, но теперь я не уверен, что я только что скрыл реальную проблему.

1 ответ

Чтобы ответить на конкретный вопрос, из документов:

Эффект — это операция, которая выполняется всякий раз, когда изменяются одно или несколько значений сигнала.

Эффекты всегда запускаются хотя бы один раз. Когда эффект запускается, он отслеживает любое чтение значений сигнала. Всякий раз, когда любое из этих значений сигнала изменяется, эффект запускается снова. Подобно вычисляемым сигналам, эффекты динамически отслеживают свои зависимости и отслеживают только те сигналы, которые были прочитаны при самом последнем выполнении.

Эффекты всегда выполняются асинхронно во время процесса обнаружения изменений.

Ваш пример очень интересен.

Это сработает , если я добавлюconsole.log()и прочитать там сигнал.

        #workingUpdate = () => {
    console.log('working', this.count());
    const c = this.count();
    this.output1.nativeElement.innerHTML = c;
  };
  #brokenUpdate = () => {
    console.log('broken', this.count());
    this.output2.nativeElement.innerHTML = this.count();
  };

Похоже, что он неправильно регистрирует сигнал для эффекта в#brokenUpdateслучай?

ОБНОВЛЕНИЕ: я получил ответ на этот вопрос от команды Angular.

По сути,brokenUpdateCase никогда не регистрирует сигнал, поскольку в первый раз выдает исключение. Таким образом, он никогда не запускается повторно при изменении сигнала.

The workingUpdatecase регистрирует сигнал перед выдачей ошибки. Поэтому он перезапускается при изменении сигнала.

Один из способов исправить это — сделать ссылки на элементы статичными, чтобы они присутствовали при запуске эффектов. Что-то вроде этого:

        @ViewChild('output1', { static: true }) output1!: ElementRef;
  @ViewChild('output2', { static: true }) output2!: ElementRef;
Другие вопросы по тегам