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

rmc*_*rry 7 reactive-programming distinct-values rxjs angular

阅读如何使用RxJ的distinctUntilChanged?,似乎distinctUntilChanged改变了输出流只提供不同的连续值

我的意思是,如果相同的值立即连续到达,则您实际上是在过滤流,并且只会出现一次重复值。

所以,如果我这样写:

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

我看不到输出与此不同:

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

我已经看过一些地方,distinctUntilChanged在订阅valueChanges表单输入时建议使用—但并不清楚为什么。

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

还是我在这里想念什么?

编辑

使用distinctUntilChanged按我的第一个代码示例中,我创建带有值的形式输入Mr Trump,并确保它被保存在模型中。

然后,我在控件内部单击并粘贴Mr Trump。由于值是相同的,所以我希望不会看到任何记录的内容-控件具有与以前相同的值,因此,当然distinctUntilChanged应该忽略它吗?

编辑2

在进一步检查我的测试后,此行为似乎是因为我使用了以下数组AbstractControls

this.itemsControl = <FormArray>this.form.controls['items']; 
...
this.itemsControl.controls[index].valueChanges...
Run Code Online (Sandbox Code Playgroud)

因此,尽管有点奇怪,当输入的值相同时它仍然会触发,但是我猜测我需要连接到valueChanges该数组项(表单组)内的实际输入,而不是数组项本身。

编辑3

因此,将EDIT 2中的代码更改为以下代码后,不会触发valueChanges(已按预期)将已经存在的相同值粘贴到输入控件中。在EDIT 2中valueChanges,钩子连接到整个formGroup,而不是单个输入控件(在本例中称为content):

let fg = this.itemsControl.controls[index]; // get the formGroup
fg['controls'].content.valueChanges
  .debounceTime(1000)
  .distinctUntilChanged()
  .subscribe(newValue => {...});
Run Code Online (Sandbox Code Playgroud)

Sim*_*ver 13

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

...完全是徒劳的!

它仅对单个值起作用(如您所说)。因此,即使没有任何变化,您也将获得新的价值。

要跟踪整个表单的更改,您需要编写一个自定义比较器,其中最简单的比较器JSON.stringify用于输出可以比较的值。在valueChanges观察到发射的对象,distinctUntilChanges是不是足够聪明,做任何事情超过了比较基准(这是给RxJS源代码的链接),除非你提供一个比较器的功能。

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

                      .subscribe(changes => { console.log('The form changed!'); });
Run Code Online (Sandbox Code Playgroud)

distinctUntilChanged对于具有原始类型的单个值,它可以很好地工作,因为===足以检测到更改。

如何解决无限循环?

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

    this.form.patchValue(address || {}, { emitEvent: false });
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,如果您只使用一些带 Angular 的 lodash 函数,请确保使用 `lodash-es` npm 包以避免导入整个库。然后你可以执行 `import { isEqual as _isEqual } from 'lodash-es';` (2认同)

Kld*_*Kld 5

使用debounceTime(1000)手段,我们仅在用户停止键入1秒钟后发送请求,在那一秒钟内用户可以写入3个字符然后将其擦除,因此输入值自上次请求以来没有变化,但是您正在发送相同的请求,以避免你可以使用.distinctUntilChanged()

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