Событие маршрутизатора с дублированным выходом switchMap - PullRequest
2 голосов
/ 16 апреля 2020

Я уже решил свою проблему, но я хотел бы понять, почему это происходит.

Я трахаю свою голову, читая и все такое, но не могу найти, почему она дублирует вывод в блоке подписки.

Вот блик стека с кодом

https://stackblitz.com/edit/angular-szwnz7

Мой ход мыслей:

Об этом компоненте, на каждое событие маршрутизатора типа NavigationEnd. Я хочу получить идентификатор раздела.

Но ничего внутри события от маршрутизатора меня не интересует. Так что я делаю switchMap с activatedRoute.queryParamMap Observable, чтобы внутри блока подписки получить идентификационный номер.

И каждый раз, когда я нажимаю между ссылками, он показывает два console.logs.

Ответы [ 2 ]

2 голосов
/ 16 апреля 2020

Я думаю, что важно упомянуть, что queryParamMap является производным от queryParams, который является BehaviorSubject:

function createActivatedRoute(c: ActivatedRouteSnapshot) {
  return new ActivatedRoute(
      new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams),
      new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
}

Источник

А вот как получается queryParamMap:

get queryParamMap(): ParamMap {
  if (!this._queryParamMap) {
    this._queryParamMap = convertToParamMap(this.queryParams);
  }
  return this._queryParamMap;
}

Источник

Под капотом, создан поток переходов . Таким образом, когда вы нажимаете кнопку, в этот поток будет вставлен новый переход , что означает, что новые маршруты должны быть активированы :

export const activateRoutes =
    (rootContexts: ChildrenOutletContexts, routeReuseStrategy: RouteReuseStrategy,
     forwardEvent: (evt: Event) => void): MonoTypeOperatorFunction<NavigationTransition> =>
        map(t => {
          new ActivateRoutes(
              routeReuseStrategy, t.targetRouterState!, t.currentRouterState, forwardEvent)
              .activate(rootContexts);
          return t;
        });

Источник

Это приведет к вызову advanceActivatedRoute и в конечном итоге эта строка будет достигнута:

(<any>route.queryParams).next(nextSnapshot.queryParams);

Таким образом, это должно быть первое сообщение, зарегистрированное на консоли.

Следующее сообщение связано с NavigationEnd событием :

(this.events as Subject<Event>)
              .next(new NavigationEnd(
                  t.id, this.serializeUrl(t.extractedUrl), this.serializeUrl(this.currentUrlTree)));

Если вы хотите визуализировать это, вы можете открыть это StackBlitz , открыть инструменты разработчика и поставить несколько точек останова:

  • router_link.ts: 265 - при нажатии на кнопку
  • activ_routes.ts: 25 - при активации маршрута
  • router.ts: 1062 - NavigationEnd событие
  • router_state.ts: 390 - advanceActivatedRoute тело ( в процессе активации маршрута)
  • app.component.ts
1 голос
/ 16 апреля 2020

Представьте себе, что this.route.queryParamMap работает как BehaviorSubject, это означает, что как только вы подписываетесь на него, вы получаете существующее значение, а новые значения приходят позже.

Теперь, чтобы объяснить ваш код, что происходит, когда вы нажмите на ссылку:

  • this.router.events испускает новый NavigationEnd, и вы переключаетесь на this.route.queryParamMap
  • this.route.queryParamMap имеет существующее значение, и это существующее значение приходит в подписку
  • this.route.queryParamMap теперь вы подписаны на эту заметку. Новое значение также появляется здесь благодаря навигации. this.router.events и this.route.queryParamMap являются независимыми Наблюдаемыми, и при навигации оба выпускают. Так что это похоже на состояние гонки. Вы получаете первое значение из-за того, что this.router.events переключено на существующее значение this.route.queryParamMap, а другое прямо из this.route.queryParamMap. И именно поэтому в подписке появляется другое значение.
...