Должен ли я отказаться от подписки на ActivatedRoute при вызове метода подписки в подписке маршрутизатора?

Я читал, что обычно вам не нужно отказываться от подписки на Router или ActivatedRoute явно потому, что:

ActivatedRoute и его наблюдаемые объекты изолированы от самого маршрутизатора. Маршрутизатор уничтожает маршрутизируемый компонент, когда он больше не нужен, и внедренный ActivatedRoute умирает вместе с ним.

источник: Нужно ли мне отказаться от подписки на наблюдаемые ActivatedRoute (например, params)?

Однако я звоню subscribe() на ActivatedRoute.firstChild.paramMap повторно в родительском компоненте app.component. Этот компонент уничтожается только тогда, когда пользователь уходит от веб-приложения или закрывает веб-сайт, поэтому я беспокоюсь, что этиparamMap подписки могут оставаться активными все время.

Звонки по подписке совершаются в течение Router.events подписка и выглядит это так:

this.routerSubscription = this.router.events
  .pipe(
    tap((event) => { 
      switch (true) {
        case event instanceof NavigationStart: { 
          setTimeout(() => this.showChildComponentLoading = true);
          break;
        }

        case event instanceof NavigationEnd:{
          this.activatedRoute.firstChild.paramMap.subscribe(paramMap => {
          if(paramMap.has('mode')){
              let newWebAppMode:string = paramMap.get('mode');
              if(this.dataStoreService.isValidWebAppMode(newWebAppMode) && newWebAppMode !== this.dataStoreService.currentAppMode)
                  this.saveToLocalStorage.next([DataType.WEB_APP_MODE, newWebAppMode]); 
          }
        });
//other code

Каждый раз, когда кто-то переходит к другому компоненту / странице activatedRoute.firstChild.paramMapподписан снова. Я должен сделать это внутри подписки маршрутизатора и только тогда, когда событие является экземпляромNavigationEnd потому что до этого параметры URL еще не доступны.

У меня вопрос: что происходит с этими подписками? Отписываются ли они автоматически или мне нужно отказываться от каждой новой подписки вручную? В последнем случае, как я могу сделать это эффективно?

Некоторые из вас могут посоветовать мне использовать activatedRoute.firstChild.snapshot.paramMap.myParameterпотому что тогда мне не нужно ни на что подписываться. Однако,snapshotне работает, если параметр url изменяется при повторном использовании того же компонента. Так что я не могу это использовать.

Спасибо

2 ответа

Да, похоже на потенциальную утечку памяти: на каждом NavigationEnd рождается новая подписка, так что у вас потенциально неограниченное количество идентичных наблюдателей одного и того же потока (и activatedRoute.firstChild.paramMapиспускает бесконечно). Вы можете убедиться в этом, поставив простойconsole.log(new Date()) внутри подписки.

я верю switchMapздесь ваш друг (он автоматически отписывается от старого потока при подписке на новый). Sth нравится

this.router.events.pipe(
    filter(event => event instanceof NavigationEnd),
    switchMap(() => this.activatedRoute.firstChild.paramMap),
    filter(paramMap => paramMap.has('mode')),
    map(paramMap => paramMap.get('mode')),
    filter(newMode => this.dataStoreService.isValidWebAppMode(newMode) && 
        newMode !== this.dataStoreService.currentAppMode),
).subscribe(newMode => this.saveToLocalStorage.next([DataType.WEB_APP_MODE, newMode]);

Кстати, разве вам не нужно остерегаться this.activatedRoute.firstChild быть нулевым?

Нет необходимости отказываться от подписки в этих случаях

  1. В случае вызовов HttpClient, потому что наблюдаемое выдает одно значение (успех или ошибка) и завершается автоматически.

  2. В случае подписки ActivatedRoute, потому что Маршрутизатор уничтожит ее, когда компонент будет уничтожен автоматически

  3. использование Async pipe

Другие вопросы по тегам