简体   繁体   English

BehaviorSubject部分更改不会触发订阅

[英]BehaviorSubject partial change does not trigger subscription

I'm working with Typescript 3.4.5 and Angular 8. 我正在使用Typescript 3.4.5和Angular 8。

Consider the following interface: 考虑以下接口:

// 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);
  }
}

The idea is to subscribe to the test$ BehaviorSubject to watch the test.content change. 这个想法是订阅test$ BehaviorSubject来观察test.content变化。

Consider now the following test: 现在考虑以下测试:

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); 
});

The console output is the following: 控制台输出如下:

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!

There is obviously a problem with "partial setter" (I don't know how to name that), when I set the instance.test.content . 设置instance.test.content时,“部分设置器”显然存在问题(我不知道如何命名)。 I carefully read the Typescript documentation on setters , but this use case is not mentioned. 我仔细阅读了setter上Typescript文档 ,但未提及该用例。

My first hypothesis was that the set test() was not called, which make sense because when I add a console.log in the setter, I don't see the "partial" set of 'aa' . 我的第一个假设是未调用set test() ,这是有道理的,因为当我在setter中添加console.log时,我看不到'aa'的“部分”设置。 But how can be the value of the behavior subject updated without triggering my subscription callback? 但是,如何在不触发我的订阅回调的情况下更新行为主体的值?

Any help or ressource will be greatly appreciated! 任何帮助或资源将不胜感激!

instance.test = {kind: 'text', content: 'fullreplace'};

This line calls the setter function 这行调用setter函数

instance.test.content = 'aa';

This line calls the getter function and then mutates the contents of the behavior subject, you should not mutate the contents of the behavior subject. 此行调用getter函数,然后对行为主体的内容进行突变,而您不应对行为主体的内容进行突变。

Get the value and then update the value with a new object, we don't mutate objects in the world of reactive programming. 获取值,然后使用新对象更新值,我们不会在反应式编程领域中更改对象。

const value = instance.test;

instance.test = { ...value, content: 'aa' };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM