作为此博客文章的一个示例,我将使用一个非常基本的示例与Angular说明真实世界的示例,但我们将重点介绍RXJS代码,而不是Angular。
startWith
可以是一个非常有用的操作员,以确保可观察到的值在订阅时立即发出值。一个很好的例子是当我们想显示一个表单值时。
在Angular中,我们可以通过类似的可观察到的形式访问形式值:formControl.valueChanges
。除了可观察到的仅在形式值变化时排放。因此,如果我们订阅它,我们将不会收到有关初始值的通知。
为了从一开始就具有当前形式的值,我们就可以执行以下操作:
export class AppComponent {
public form = new FormControl(null);
public formValue$ = this.form.valueChanges.pipe(startWith(this.form.value));
}
我们可以看到到目前为止,它可以按预期工作,而初始的null
值是从开始时显示的。
也就是说,这可能会导致偷偷摸摸的问题。
在上面的示例中,尝试将表单值更改为您喜欢的任何东西。然后,您将看到绑定将显示新值。然后,使用“切换”按钮隐藏该值并再次显示。它将显示null
,而不是真实/当前表单值。
起初为什么会发生这种情况可能有些误导。原因是因为startWith
。尽管可以观察到的天性很冷,但一旦实例化,startWith
功能就会立即运行。这只是一个函数,这不是任何回调的一部分。最初,形式值是null
,因为我们已经设置了它。因此,我们第一次订阅可观察到的,这很好。
然后,我们取消订阅,在这种情况下,使用toggle + ngIf
删除了整个节点,而async
管道为我们取消订购。当我们再次切换值并将ngIf
变为true
时,我们再次订阅可观察到的可观察值,正如我们提到的那样,它在创建了类的时候就在startWith
函数上运行,因此它将永久设置为初始形式值:null
。<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /p>
要解决这个问题,这是我们可以做的:
public formValue$ = concat(
defer(() => of(this.form.value)),
this.form.valueChanges
);
使用concat
,我们说我们将使用一个内部流开始我们的流,一旦完成,请继续从另一个流开始。
第一个是这里的关键。使用defer
,每当订阅时,它将运行延期回调,而不是与startWith
实例化一旦实例化。
这意味着,每当我们再次订阅可观察到的时,我们都会在此时获得表单值 ,而不是在班级实例化时。
这是最终代码和实时演示:
确实指出,这种特殊情况是有一个有点现实的示例,即使要显示当前形式的值,我们只使用form.value
并使用它,而没有任何可观察或异步管道。可以在您使用startWith
,from
,of
的任何地方应用此功能,以在订阅时获得一个值,而不是在读取代码时。如果有错误,可以重新进行流时,它也可能很有用。
如果您对有关Angular,RXJ,开源,自托管,数据隐私的更多文章感兴趣,请随时点击“关注”按钮以获取更多信息。感谢您的阅读!