Частичное изменение BehaviorSubject не вызывает подписку - PullRequest
0 голосов
/ 13 июня 2019

Я работаю с 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. Я внимательно прочитал документацию Typescript по сеттерам , но этот вариант использования не упоминается.

Моя первая гипотеза состояла в том, что set test() не был вызван, что имеет смысл, потому что, когда я добавляю console.log в сеттер, я не вижу "частичного" набора 'aa'. Но как можно обновить значение темы поведения, не вызывая мой обратный вызов подписки?

Любая помощь или ресурсы будут с благодарностью!

1 Ответ

3 голосов
/ 13 июня 2019
instance.test = {kind: 'text', content: 'fullreplace'};

Эта строка вызывает функцию установки

instance.test.content = 'aa';

Эта строка вызывает функцию получения и затем изменяет содержимое субъекта поведения, вам не следует изменять содержимое субъекта поведения.

Получите значение, а затем обновите значение новым объектом, мы не изменяем объекты в мире реактивного программирования.

const value = instance.test;

instance.test = { ...value, content: 'aa' };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...