Angular Zoneless:更改基于对象的信号的属性值会意外更新视图

问题描述 投票:0回答:1

我有一个使用无区域更改检测的 Angular v18.2 应用程序:

export const appConfig: ApplicationConfig = {  
  providers: [provideExperimentalZonelessChangeDetection(), provideRouter(routes)]  
};

zone.js
Polyfill 也已从
angular.json
中删除。

我有一个使用对象作为信号的计数器组件:

counter.component.ts:

interface CounterModel {  
  value: number  
}  
  
@Component({  
  selector: 'app-counter',  
  standalone: true,  
  imports: [],  
  templateUrl: './counter.component.html',  
  styleUrl: './counter.component.scss',  
  changeDetection: ChangeDetectionStrategy.OnPush  
})  
export class CounterComponent {  
  counterModel: WritableSignal<CounterModel> = signal({  
    value: 0  
  })  
  
  increment() {  
    this.counterModel().value++  
  }  
  
  decrement() {  
    this.counterModel().value--  
  }  
}

counter.component.html:

<p>{{ counterModel().value }}</p>  
<button (click)="decrement()">Decrement</button>  
<button (click)="increment()">Increment</button>

注意

increment
decrement
方法只是更新对象的
value
属性。它们不会更改信号的对象引用。鉴于此,我希望更改检测不会运行,并且单击“递减/增量”按钮时视图不会更新。

但是,与我的预期相反,视图确实更新了。这是为什么?显然,我不理解有关无区域变化检测和信号的一些内容。

此外,我可以放心地依赖这种行为吗?或者更新

CounterModel.value
属性以使用嵌套信号更好,或者在
CounterModel
increment
方法中创建
decrement
的新实例?如果您能在这里获得有关最佳实践的指导,我们将不胜感激。

angular angular2-changedetection angular-signals zoneless
1个回答
0
投票

您单击的按钮会将组件标记为脏,因此正在运行更改检测,因为对象只是内存引用。当视图刷新时更新内部属性时,最新值会显示在 UI 中,下面是

setInterval
调用相同函数但视图不更新的示例。

import {
  Component,
  provideExperimentalZonelessChangeDetection,
  ChangeDetectionStrategy,
  WritableSignal,
  signal,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

interface CounterModel {
  value: number;
}

@Component({
  selector: 'app-root',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <p>{{ counterModel().value }}</p>  
    <button (click)="decrement()">Decrement</button>  
    <button (click)="increment()">Increment</button>
  `,
})
export class App {
  counterModel: WritableSignal<CounterModel> = signal({
    value: 0,
  });

  ngOnInit() {
    setInterval(() => {
      this.increment();
    }, 1000);
  }

  increment() {
    this.counterModel().value++;
  }

  decrement() {
    this.counterModel().value--;
  }
}

bootstrapApplication(App, {
  providers: [provideExperimentalZonelessChangeDetection()],
});

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.