Должен ли я отказаться от подписки на 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
быть нулевым?
Нет необходимости отказываться от подписки в этих случаях
В случае вызовов HttpClient, потому что наблюдаемое выдает одно значение (успех или ошибка) и завершается автоматически.
В случае подписки ActivatedRoute, потому что Маршрутизатор уничтожит ее, когда компонент будет уничтожен автоматически
использование Async pipe