RXJS:使用“ startwith”时避免一个简单的错误
#javascript #angular #rxjs

作为此博客文章的一个示例,我将使用一个非常基本的示例与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并使用它,而没有任何可观察或异步管道。可以在您使用startWithfromof的任何地方应用此功能,以在订阅时获得一个值,而不是在读取代码时。如果有错误,可以重新进行流时,它也可能很有用。

如果您对有关Angular,RXJ,开源,自托管,数据隐私的更多文章感兴趣,请随时点击“关注”按钮以获取更多信息。感谢您的阅读!