Странное поведение при использовании объектов / эмиттеров событий в службах для межкомпонентной связи в angular? - PullRequest
0 голосов
/ 29 мая 2020

Я хочу понять, как работают наблюдаемые, субъекты и субъекты поведения (прочитал много статей, просмотрел много видео, но мне все еще не ясно, поскольку я не смог объяснить это поведение), поэтому я создал этот простой пример и получил неожиданное поведение. У меня есть два компонента: родительский компонент и дочерний компонент .

Родительский компонент отображает список имен фотографий с кнопками для отображения деталей. При нажатии этой кнопки происходит переход к дочернему компоненту, где i wi sh отображает отдельную фотографию вместе с деталями. Итак, это идея.

Я использовал службу, где у меня есть тема. Теперь всякий раз, когда нажимается кнопка в родительском компоненте, я передаю значение из объекта. Я хочу зафиксировать это значение в своем дочернем компоненте, поэтому подписываюсь на него.

Странное поведение - при первом щелчке я не вижу никаких данных в моем дочернем компоненте. Затем щелкните одно значение в дочернем компоненте. Третий щелчок по двум значениям в дочернем компоненте и так далее ....

Вот мои компоненты -

parent.component.ts

export class ParentComponent implements OnInit {
  photoList = [
    {
      albumId: 1,
      id: 1,
      title: "accusamus beatae ad facilis cum similique qui sunt",
      url: "https://via.placeholder.com/600/92c952",
      thumbnailUrl: "https://via.placeholder.com/150/92c952",
    },
    {
      albumId: 1,
      id: 2,
      title: "reprehenderit est deserunt velit ipsam",
      url: "https://via.placeholder.com/600/771796",
      thumbnailUrl: "https://via.placeholder.com/150/771796",
    },
    {
      albumId: 1,
      id: 3,
      title: "officia porro iure quia iusto qui ipsa ut modi",
      url: "https://via.placeholder.com/600/24f355",
      thumbnailUrl: "https://via.placeholder.com/150/24f355",
    },
  ];
  constructor(private _talkService: TalkService, private router: Router) {}

  ngOnInit() {}

  displayName(id, url, thumbnailUrl) {
    console.log({ id, url, thumbnailUrl });

    //this._talkService.talk.emit({ url, thumbnailUrl });
    this._talkService.talk.next({ id, url, thumbnailUrl });
    this.router.navigate(["/photo"]);
  }
}

child.component.ts

export class ChildComponent implements OnInit {
  constructor(private _talkService: TalkService) {}

  ngOnInit() {
    console.log("child component created");
    this._talkService.talk.subscribe((data) => {
      console.log(data);
    });
  }
}

talk.service.ts

@Injectable({
  providedIn: "root",
})
export class TalkService {
  // talk = new EventEmitter();
  talk = new Subject();
  constructor() {}
}

Вывод журналов консоли

App with console logs

Я использовал эти три -

Источники событий -> такое же поведение, как описано Субъекты -> такие же поведение, как описано Поведение Субъекты -> Я также получаю первое значение (поскольку это помогает нам получить ранее выданное значение, эту часть я понимаю). Здесь также приветствуется подробное объяснение.

Я ожидал, что при каждом щелчке будет одно значение, но это не тот случай. Может кто-нибудь объяснить мне поведение. Это должно быть наблюдаемая работа, и я не могу ее получить.

Вот ссылка на мой репозиторий github -

исходный код github

1 Ответ

1 голос
/ 30 мая 2020

Звучит как классная c утечка памяти. Каждый раз, когда вы подписываетесь на talkService.talk, вы создаете подписку, которая будет очищена только после отмены подписки. Таким образом, даже несмотря на то, что дочерние компоненты кажутся уничтоженными, когда вы go возвращаетесь к родительскому компоненту, подписка все еще существует и ведет журнал консоли каждый раз, когда субъект talk выдает новое значение. Вы должны отказаться от подписки, когда дочерний компонент будет уничтожен. Простой способ убедиться, что подписка отменена, - использовать канал async в шаблоне html.

child.component.ts

export class ChildComponent implements OnInit {
  data$: Observable<any> = this.talkService.talk;

  constructor(private talkService: TalkService) {}
}

child.component. html

{{ data$ | async }}

Кроме того, вы можете вернуться к использованию BehaviorSubject, поскольку дочерний компонент будет подписаться на talk после передачи значения из родительского компонента.

...