FormControl.detectchanges - 为什么要使用distinctUntilChanged?

问题描述 投票:6回答:2

阅读How to use RxJs distinctUntilChanged?this,似乎distinctUntilChanged改变输出流只提供不同的连续值。

我认为这意味着如果相同的值立即连续到达,您实际上是过滤流并且只获得该重复值的一次出现。

所以,如果我这样写:

this.myFormControl.valueChanges
  .debounceTime(1000)
  .distinctUntilChanged()
  .subscribe(newValue => {
    console.log('debounced: ', newValue);
  });

我看到输出没有区别:

this.myFormControl.valueChanges
  .debounceTime(1000)
  .subscribe(newValue => {
    console.log('debounced: ', newValue);
  });

我已经看到一些地方建议在表单输入上订阅distinctUntilChanged时使用valueChanges - 但是真的不明白为什么。

这是一个输入,所以如果用户输入它总是在变化,对吗?这些值将始终是不同的,因此您只需添加一个额外的操作来无缘无故地过滤输入。

或者我在这里遗漏了什么?

编辑

根据我的第一个代码示例使用distinctUntilChanged,我创建了一个值为Mr Trump的表单输入,并确保它保存在模型中。

然后我点击控件内部并粘贴Mr Trump。由于值是相同的,我原本预计不会看到任何记录 - 控件具有与之前相同的值,所以distinctUntilChanged肯定应该忽略它?

编辑2

在进一步研究我的测试之后,这种行为似乎是因为我使用了一个AbstractControls数组:

this.itemsControl = <FormArray>this.form.controls['items']; 
...
this.itemsControl.controls[index].valueChanges...

所以虽然有点奇怪,当输入的值相同时它仍然会触发,我猜我需要连接到这个数组项(表单组)中实际输入的valueChanges,而不是数组项本身。

编辑3

因此,在将EDIT 2中的代码更改为以下内容后,将已存在的相同值粘贴到输入控件中不会触发valueChanges(如预期的那样)。在编辑2中valueChanges被连接到整个formGroup,而不是单独的输入控件(在这种情况下称为content):

let fg = this.itemsControl.controls[index]; // get the formGroup
fg['controls'].content.valueChanges
  .debounceTime(1000)
  .distinctUntilChanged()
  .subscribe(newValue => {...});
angular rxjs reactive-programming distinct-values
2个回答
5
投票

使用debounceTime(1000)意味着我们只在用户停止键入1秒钟时才发送请求,在此期间用户可以写入3个字符然后擦除它们,因此输入值自上次请求后没有改变但是您发送的是相同的请求,避免你可以使用.distinctUntilChanged()

  this.myFormControl.valueChanges
      .debounceTime(1000)
      .distinctUntilChanged()
      .subscribe(newValue => {
        console.log('debounced: ', newValue)
      });

10
投票

distinctUntilChanged应用于valueChanges可观察到...

......完全是徒劳的!

它只能按预期在单个值上工作(正如您所说)。所以即使没有任何改变,你也会得到一个新的价值。

要跟踪整个表单的更改,您需要编写自定义比较器,其中最简单的使用JSON.stringify输出可以比较的值。 valueChanges observable发出一个对象,除非你提供比较器函数,否则distinctUntilChanges除了reference compare(这是RxJS源代码的链接)之外的任何事情都不够聪明。

this.form.valueChanges.pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === 
                                                           JSON.stringify(b)))

                      .subscribe(changes => { console.log('The form changed!'); });

distinctUntilChanged适用于具有原始类型的单个值,因为===足以检测变化。

How do I solve infinite loops?

如果您尝试将distinctUntilChanges添加到管道中(对于整个表单)以避免在以编程方式更新表单值时出现无限循环 - 您可能需要这样做:

    this.form.patchValue(address || {}, { emitEvent: false });
© www.soinside.com 2019 - 2024. All rights reserved.