Angular v16中使用Effects时如何监听特定Signal的变化?
在Angular多个Signal中定位触发Effect的特定Signal
当组件中有多个Signal时,要识别具体哪个Signal触发了Effect,可以用以下几种方法:
方法1:对比新旧值+untracked隔离非目标Signal
通过onCleanup记录上一次的值,同时用untracked包裹非目标Signal的读取,避免Effect被它们触发:
import { effect, untracked, signal } from '@angular/core'; @Component({...}) export class YourComponent { value1 = signal(0); value2 = signal('initial'); constructor() { const targetSignal = this.value1; effect((onCleanup) => { const currentVal = targetSignal(); let previousVal: typeof currentVal | undefined; // 清理时保存当前值作为下一次的旧值 onCleanup(() => { previousVal = currentVal; }); // 仅当值发生变化时执行逻辑 if (previousVal !== undefined && previousVal !== currentVal) { console.log('value1 发生变化:', previousVal, '→', currentVal); } // 用untracked读取其他Signal,不会让Effect追踪它们 untracked(() => { console.log('当前value2的值:', this.value2()); }); }); } }
方法2:用computed隔离目标Signal
先创建只依赖目标Signal的计算信号,Effect只读取这个计算信号,这样只有目标Signal变化时才会触发Effect:
import { effect, computed, signal } from '@angular/core'; @Component({...}) export class YourComponent { value1 = signal(0); value2 = signal('initial'); // 仅依赖value1的计算信号 value1Tracker = computed(() => this.value1()); constructor() { effect(() => { console.log('value1 发生变化:', this.value1Tracker()); // 这里读取value2不会触发Effect,除非value1同时变化 console.log('value2 当前值:', this.value2()); }); } }
方法3:给Signal绑定变化标记
通过包装Signal的set/update/mutate方法,添加变化标记,在Effect中检查标记来判断哪个Signal发生了变化:
import { effect, signal, WritableSignal } from '@angular/core'; @Component({...}) export class YourComponent { value1 = signal(0); value2 = signal('initial'); private value1Changed = signal(false); private value2Changed = signal(false); constructor() { // 包装Signal,添加变化标记逻辑 this.value1 = this.wrapWithChangeMark(this.value1, this.value1Changed); this.value2 = this.wrapWithChangeMark(this.value2, this.value2Changed); effect(() => { // 读取所有Signal,确保Effect能被它们触发 const v1 = this.value1(); const v2 = this.value2(); if (this.value1Changed()) { console.log('value1 发生变化:', v1); this.value1Changed.set(false); // 重置标记 } if (this.value2Changed()) { console.log('value2 发生变化:', v2); this.value2Changed.set(false); } }, { allowSignalWrites: true }); // 允许在Effect中修改Signal } private wrapWithChangeMark<T>( targetSignal: WritableSignal<T>, markSignal: WritableSignal<boolean> ): WritableSignal<T> { // 保存原方法 const originalSet = targetSignal.set; const originalUpdate = targetSignal.update; const originalMutate = targetSignal.mutate; // 重写set方法,更新标记 targetSignal.set = (val: T) => { markSignal.set(true); originalSet.call(targetSignal, val); }; // 重写update方法 targetSignal.update = (updater: (val: T) => T) => { markSignal.set(true); originalUpdate.call(targetSignal, updater); }; // 重写mutate方法 targetSignal.mutate = (mutator: (val: T) => void) => { markSignal.set(true); originalMutate.call(targetSignal, mutator); }; return targetSignal; } }
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

