По умолчанию маршрутизатор Angular 2 использует компоненты повторно, если текущий и будущий маршруты совпадают. В этом посте показано, как эта стратегия влияет на реализацию компонента и как эту стратегию можно изменить.

Устаревший компонент

Вот пример компонента, который показывает устаревшие данные. Когда маршрут приложения изменяется с «/ detail / 1» на «/ detail / 2», компонент DetailStaleComponent по-прежнему показывает начальный параметр 1.

import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from '@angular/router';

@Component({
  selector: 'app-detail-stale',
  template: '<p>detail stale for {{id}} param</p>'
})
export class DetailStaleComponent implements OnInit {
  id: string;

  constructor(private route: ActivatedRoute) {
  }

  ngOnInit() {
    this.id = this.route.snapshot.params['id'];
  }
}

Подпишитесь на изменения

Компонент должен подписаться на изменения параметров маршрута и обновлять свою модель / представление, когда маршрут приложения изменяется с «/ detail / 1» на «/ detail / 2». Метод компонента ngOnInit получает доступ к наблюдаемым параметрам ActivatedRoute и использует асинхронный конвейер для поддержания параметра в актуальном состоянии.

import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/pluck';

@Component({
  selector: 'app-detail-reusable',
  template: `<p>detail reusable for {{id$| async}} param </p>`
})
export class DetailReusableComponent implements OnInit {
  id$: Observable<string>;

  constructor(private route: ActivatedRoute) {
  }

  ngOnInit() {
    this.id$ = this.route.params.pluck('id');
  }
}

RouteReuseStrategy

Маршрут Angular 2 позволяет изменить стратегию повторного использования по умолчанию. В этом примере показано, как настраиваемый RouteReuseStrategy помогает устранить устаревшие данные в ситуации, когда компонент не использует подписку.

Angular 2 использует DefaultRouteReuseStrategy, если приложение не предоставляет настраиваемую. DefaultRouteReuseStrategy реализует интерфейс RouteReuseStrategy, который определяет метод shouldReuseRoute, который используется маршрутизатором для принятия решения о повторном использовании.

export abstract class RouteReuseStrategy {
  /** Determines if this route (and its subtree) should be detached to be reused later */
  abstract shouldDetach(route: ActivatedRouteSnapshot): boolean;

  /** Stores the detached route */
  abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void;

  /** Determines if this route (and its subtree) should be reattached */
  abstract shouldAttach(route: ActivatedRouteSnapshot): boolean;

  /** Retrieves the previously stored route */
  abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle;

  /** Determines if a route should be reused */
  abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean;
}

Давайте определим нашу собственную CustomRouteReuseStrategy, которая не позволяет повторно использовать наш компонент DetailSameComponent. Компонент DetailSameComponent идентичен компоненту DetailStaleComponent, определенному выше.

import {DefaultRouteReuseStrategy} from '@angular/router/src/router';
import {ActivatedRouteSnapshot} from '@angular/router';

export class CustomRouteReuseStrategy extends DefaultRouteReuseStrategy {
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    let name = future.component && (<any>future.component).name;
    return super.shouldReuseRoute(future, curr) && name !== 'DetailSameComponent';
  }
}

Стратегия - это сервис Angular 2, который должен быть зарегистрирован в модуле.

@NgModule({
  declarations: [AppComponent, ListComponent, DetailReusableComponent, DetailStaleComponent, DetailSameComponent],
  imports: [BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(routes)],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: CustomRouteReuseStrategy
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

И вот результат - компонент показывает правильные данные после изменения маршрута с «/ detail / 1» на «/ detail / 2».

Вот ссылка на репозиторий github angular2-router-reuse, содержащий полный код.