在孩子中,我有一个字段
data
,单击后我可以更改它的内容。然后,我希望父级产生一个效果来触发检测所述更改。由于某种原因,当我更改子级中的模型输入时,该效果不会触发(但是,在父级中设置信号时,该效果会触发。
孩子有这个。
export class ChildComponent {
data = model({} as Vm);
onClick() {
console.log("Click alters the data.");
// this.data.set(this.data());
this.data.update(a => a);
}
}
家长有这个。
export class ParentComponent {
constructor() {
interval(1000).subscribe(a => console.log("poll: ", this.data()));
effect(() => { console.log("effect: ", this.data()) });
}
data = signal({} as Vm);
ngOnInit() { this.data.set(this.getData()); }
}
我看到初始效果显示一个空对象。然后,我看到来自父级 init 方法的更新。我还看到第二次检查显示子项中更改的值。然而 - 该效果不会再次触发,只会触发上述两次。
我不知道如何进一步排除故障。检查官方文档,我发现它应该可以工作(它确实可以工作!),但我完全确定我是否完全正确地在子组件中执行了更改。
(在实际场景中,我只会更改数组中对象中的一个字段,该数组是
data
模型输入的一部分,但这是下一步。首先,我想了解为什么这样做 set(...)
也不update(...)
在角色中触发效果。
仅当实际值更改时才会触发信号,因为数组和对象作为引用存储在内存中,如果更改内部属性,内存引用不会更改,因此不会将其检测为更改。
Angular 18 中的信号和数组可变性 - Ben Nadel
Github 问题 - Angular 17 - 不支持可变信号
您可以使用
object destructuring
(对于对象)或 .slice()
数组方法(仅限数组)来创建新的内存引用,这将传播到父级。由于内存引用发生了变化,信号将把它作为新的变化来拾取。
@Component({
selector: 'app-child',
standalone: true,
template: `
<button (click)="onClick()">click</button>
`,
})
export class ChildComponent {
data = model({});
onClick() {
console.log('Click alters the data.');
// this.data.set(this.data());
// object destructuring creates new memory reference.
this.data.update((a: any) => ({ ...a }));
}
}
import { Component, effect, model, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { interval } from 'rxjs';
@Component({
selector: 'app-child',
standalone: true,
template: `
<button (click)="onClick()">click</button>
`,
})
export class ChildComponent {
data = model({});
onClick() {
console.log('Click alters the data.');
// this.data.set(this.data());
this.data.update((a: any) => ({ ...a }));
}
}
@Component({
selector: 'app-root',
standalone: true,
imports: [ChildComponent],
template: `
<app-child [(data)]="data" (dataChange)="dataChange($event)"/>
`,
})
export class App {
data = signal({});
constructor() {
// interval(1000).subscribe((a: any) => console.log('poll: ', this.data()));
effect(() => {
console.log('effect: ', this.data());
});
}
ngOnInit() {
// this.data.set(this.getData());
}
dataChange(e: any) {
console.log(e);
}
}
bootstrapApplication(App);