我有一个使用无区域更改检测的 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
的新实例?如果您能在这里获得有关最佳实践的指导,我们将不胜感激。
您单击的按钮会将组件标记为脏,因此正在运行更改检测,因为对象只是内存引用。当视图刷新时更新内部属性时,最新值会显示在 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()],
});