角度信号中效应函数的用例是什么?
它不会返回任何内容,并且默认情况下,您无法更新效果中的其他信号(我知道您可以禁用此功能,但我认为这不是一个好的做法)...那么在什么情况下它有用?从服务器获取数据的最佳方法是什么?想象一下,您有一个返回可观察值的服务,并且您想在信号发生变化时调用该服务,最佳实践是什么?
现在我正在使用这样的代码(这个具体示例中涉及一些rx.js)
protected options = toSignal(
combineLatest([toObservable(this.timeFrame)]).pipe(
switchMap(([timeFrame]) => {
if (!timeFrame) {
return of([]);
}
return this.myService.fetchData(timeFrame); // this returns an observable.
}),
),
);
效果的常见用例在官方文档
中有详细描述
- 记录正在显示的数据以及数据何时发生变化,用于分析或作为调试工具
- 与 window.localStorage 保持数据同步
- 添加无法用模板语法表达的自定义 DOM 行为
- 对图表库或其他第三方 UI 库执行自定义渲染
根据定义,它是一项功能,使您能够在效果内部使用的信号之一发生更改时执行任何操作。
您写道它不会返回任何内容,但这是不正确的。它返回 EffectRef ,可用于清理,就像处理可观察量/事件侦听器/间隔等一样。
我想说,调用有效服务的情况可能需要响应,也可能不需要响应。
如果您不需要响应,那么直接调用它就没有问题,例如当您只发送请求而不等待响应时跟踪用户操作。
如果您需要来自服务器的数据,则可能会有不同的使用场景。它可以仅用于日志、警报消息,或者您确实需要在 UI 上使用它。
通过前两个(警报、日志),很明显效果完全没问题。
对于模板所需的响应数据的情况,我会深入研究信号/效果的工作原理,以了解使用它是否有危险。
何时不使用效果
避免使用效果来传播状态变化。这可能会导致 ExpressionChangedAfterItHasBeenChecked 错误、无限循环更新或不必要的更改检测周期。
由于这些风险,默认情况下不允许设置信号,但如果绝对必要,可以启用。
他们不建议进行状态更改。但让我们涵盖所有这些情况
在更改检测过程中,效果始终异步执行。 所以如果你这样做
constructor() {
effect(() => {
this.isExceeded.set(this.prop() > 3)
});
}
onClick(): void {
this.prop.update(p => p + 1);
}
您应该了解,每当您的
onClick
处理程序执行完成时,zone.js 都会触发更改检测周期。 effect
正如文档所说将异步运行,因此它将在更改检测期间或之后触发,这将导致此ExpressionChangedAfterItHasBeenChecked
异常。
effect(() => this.prop.set(this.prop() + 1))
在你写的例子中,我真的看不出做这样的事情有任何问题:
protected options = signal([]);
#sub: Subscription | null = null;
constructor() {
effect(() => {
if(this.#sub) this.#sub.unsubscribe(); // cancel previous ongoing request if it's pending
this.#sub = this.myService.fetchData(timeFrame).subscribe(response => {
this.options.set(response);
});
}, { allowSignalWrites: true });
}
乍一看,当你看到
allowSignalWrites: true
时,它看起来很可怕,但如果我们深入研究它并尝试理解这段代码可能会发生什么问题 - 我找不到它的任何潜在问题,因为信号集不是直接在效果的根级别执行的但在另一个异步操作的回调中,这里是服务调用。因此,如果您启用了 zone.js,则更改检测将在执行订阅回调后开始执行,因此信号将在 CD 开始工作之前设置。如果没有 zone.js 并使用信号组件方法,那么信号更改将在下一个刻度上触发组件视图的更改检测,因此没有问题。
所以以上3个问题点中任何一个的0气味都在这里。