FormControl.detectchanges - 为什么使用 distinctUntilChanged?
FormControl.detectchanges - why use distinctUntilChanged?
阅读 and 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);
});
我看到一些地方建议在表单输入上订阅 valueChanges
时使用 distinctUntilChanged
— 但我不太明白为什么。
这是一个输入,所以如果用户正在输入,它总是在变化,对吧?这些值将始终不同,因此您只是无缘无故地添加了一个额外的操作来过滤输入。
还是我遗漏了什么?
编辑
根据我的第一个代码示例使用 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
(如预期)。在 EDIT 2 中,valueChanges
连接到整个 formGroup
,而不是单独的输入控件(在本例中称为 content
):
let fg = this.itemsControl.controls[index]; // get the formGroup
fg['controls'].content.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.subscribe(newValue => {...});
使用debounceTime(1000)
意味着我们只在用户停止输入1秒时发送请求,在那一秒内用户可以输入3个字符然后擦除它们,所以输入值自上次请求以来没有改变但是您发送相同的请求,以避免您可以使用 .distinctUntilChanged()
this.myFormControl.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.subscribe(newValue => {
console.log('debounced: ', newValue)
});
distinctUntilChanged
当应用于 valueChanges
可观察...
...可能永远无法工作!
它仅在单个值上按预期工作(如您所说)。所以即使什么都没有改变,你也会得到一个新的值。
要跟踪整个表单的更改,您需要编写自定义比较器,其中最简单的使用 JSON.stringify
来输出可以比较的值。 valueChanges
observable 发出一个对象,而 distinctUntilChanges
不够聪明,无法做任何超出 reference compare 的事情(这是 RxJS 源代码的 link ),除非你提供一个比较器功能。
this.form.valueChanges.pipe(distinctUntilChanged((a, b) => JSON.stringify(a) ===
JSON.stringify(b)))
.subscribe(changes => { console.log('The form changed!'); });
distinctUntilChanged
适用于原始类型的单个值,因为 ===
足以检测更改。
如何解决无限循环?
如果您尝试将 distinctUntilChanges
添加到您的管道(对于整个表单)以避免在以编程方式更新表单值时出现无限循环 - 您可能需要这样:
this.form.patchValue(address || {}, { emitEvent: false });
阅读 distinctUntilChanged
将输出流更改为仅提供 不同的连续值。
我认为这意味着如果相同的值立即连续到达,您实际上是在过滤流并且只得到该重复值的一次出现。
所以如果我这样写:
this.myFormControl.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.subscribe(newValue => {
console.log('debounced: ', newValue);
});
我看不出输出有什么不同:
this.myFormControl.valueChanges
.debounceTime(1000)
.subscribe(newValue => {
console.log('debounced: ', newValue);
});
我看到一些地方建议在表单输入上订阅 valueChanges
时使用 distinctUntilChanged
— 但我不太明白为什么。
这是一个输入,所以如果用户正在输入,它总是在变化,对吧?这些值将始终不同,因此您只是无缘无故地添加了一个额外的操作来过滤输入。
还是我遗漏了什么?
编辑
根据我的第一个代码示例使用 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
(如预期)。在 EDIT 2 中,valueChanges
连接到整个 formGroup
,而不是单独的输入控件(在本例中称为 content
):
let fg = this.itemsControl.controls[index]; // get the formGroup
fg['controls'].content.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.subscribe(newValue => {...});
使用debounceTime(1000)
意味着我们只在用户停止输入1秒时发送请求,在那一秒内用户可以输入3个字符然后擦除它们,所以输入值自上次请求以来没有改变但是您发送相同的请求,以避免您可以使用 .distinctUntilChanged()
this.myFormControl.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.subscribe(newValue => {
console.log('debounced: ', newValue)
});
distinctUntilChanged
当应用于 valueChanges
可观察...
...可能永远无法工作!
它仅在单个值上按预期工作(如您所说)。所以即使什么都没有改变,你也会得到一个新的值。
要跟踪整个表单的更改,您需要编写自定义比较器,其中最简单的使用 JSON.stringify
来输出可以比较的值。 valueChanges
observable 发出一个对象,而 distinctUntilChanges
不够聪明,无法做任何超出 reference compare 的事情(这是 RxJS 源代码的 link ),除非你提供一个比较器功能。
this.form.valueChanges.pipe(distinctUntilChanged((a, b) => JSON.stringify(a) ===
JSON.stringify(b)))
.subscribe(changes => { console.log('The form changed!'); });
distinctUntilChanged
适用于原始类型的单个值,因为 ===
足以检测更改。
如何解决无限循环?
如果您尝试将 distinctUntilChanges
添加到您的管道(对于整个表单)以避免在以编程方式更新表单值时出现无限循环 - 您可能需要这样:
this.form.patchValue(address || {}, { emitEvent: false });