angular - BehaviorSubject 部分更改不会触发订阅
问题描述
我正在使用 Typescript 3.4.5 和 Angular 8。
考虑以下接口:
// This is an interface which represents a piece of data, which will be partially updated
export interface TextBrick {
kind: 'text';
content: string;
}
export class TestService {
test$ = new BehaviorSubject<TextBrick>({kind: 'text', content: 'initial'});
get test(): TextBrick {
return this.test$.value;
}
set test(v: TextBrick) {
console.log('set', v);
this.test$.next(v);
}
}
这个想法是订阅test$
BehaviorSubject 以观察test.content
变化。
现在考虑以下测试:
test('test', () => {
const instance = new TestService();
// Watch subscription
instance.test$.subscribe((v) => console.log('sub', v));
// 1) Full replace, subscription triggered
instance.test = {kind: 'text', content: 'fullreplace'};
// 2) Partial replace, subscription not triggered
instance.test.content = 'aa';
// But the value of the BehaviorSubject was updated! WTF?!
console.log('end', instance.test);
});
控制台输出如下:
sub { kind: 'text', content: 'intitial' } // Expected behavior
set { kind: 'text', content: 'fullreplace' } // Expected behavior
sub { kind: 'text', content: 'fullreplace' } // Expected behavior
end { kind: 'text', content: 'aa' } // Sounds really weird!
当我设置instance.test.content
. 我仔细阅读了关于 setters 的 Typescript 文档,但没有提到这个用例。
我的第一个假设是set test()
没有被调用,这是有道理的,因为当我在 setter 中添加 console.log 时,我看不到'aa'
. 但是如何在不触发我的订阅回调的情况下更新行为主题的值呢?
任何帮助或资源将不胜感激!
解决方案
instance.test = {kind: 'text', content: 'fullreplace'};
此行调用 setter 函数
instance.test.content = 'aa';
此行调用 getter 函数然后改变行为主体的内容,您不应该改变行为主体的内容。
获取值,然后用新对象更新值,我们不会在反应式编程的世界中改变对象。
const value = instance.test;
instance.test = { ...value, content: 'aa' };
推荐阅读
- aws-lambda - 无服务器部署具有特定依赖关系的 lambda@edge
- r - 将三个情节合二为一
- react-native - 使用 react-navigation-tab 创建一个自定义的可滚动顶部标签栏?
- networking - 运行 VPN 客户端软件时客户端实际发生的情况
- node.js - NodeJS 路由顺序
- install4j - 为什么 Install4j 无法解析带有 SAXParseException 的 updates.xml 文件?
- reactjs - 具有状态值的重复组件 [更新问题代码]
- php - 将图像保存到 PHP 会话
- javascript - Javascript识别句子,无论句子中的任何地方大小写
- pandas - 熊猫:从列表中删除括号?