プロバイダを使うと、Angularのルーティングとコンポーネントのライフサイクルの振る舞いを制御できます。
コンポーネントを切り替えるとき、Angularは前のコンポーネントを破棄して新しいコンポーネントを作成します。コンポーネントがロードされるたびに、HTTPリクエストのような高価な処理が発生する可能性があるからです。
そこでRouteReuseStrategyの登場です。
RouteReuseStrategy
RouteReuseStrategy インタフェースは、5 つのメソッドを宣言します。
shouldReuseRoute
このメソッドはルートが切り替わるたびに呼び出されます。future パラメータは残されるルートで、curr パラメータはロードされるルートです。このメソッドがtrueを返す場合、ルートはジャンプしません。false を返した場合、ルートは変更され、残りのメソッドが呼び出されます。
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
// デフォルトの動作
return future.routeConfig === curr.routeConfig;
}
shouldAttach
ルートがオープンされたばかりで、コンポーネントがこのルートにロードされると shouldAttach が呼び出されます。このメソッドはコンポーネントがロードされるとすぐに呼び出されます。このメソッドが true を返す場合、retrieve メソッドが呼び出されます。そうでない場合、コンポーネントは再作成されます。
shouldAttach(route: ActivatedRouteSnapshot): boolean;
retrieve
このメソッドは、shouldAttach メソッドが true を返すと呼び出されます。現在のルートのパラメータを提供し、キャッシュされた RouteHandle を返します。このメソッドを使用すると、キャッシュされた RouteHandle を手動で取得することができます。
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null;
shouldDetach
このメソッドは、現在のルートから離れるときに呼び出されます。trueが返された場合、storeメソッドが呼び出されます。
shouldDetach(route: ActivatedRouteSnapshot): boolean;
store
このメソッドは、shouldDetach メソッドが true を返したときにのみ呼び出されます。ここでは、RouteHandle のキャッシュ方法を指定できます。このメソッドでキャッシュされた内容は、retrieve メソッドで使用されます。これは、離脱ルートと RouteHandle を提供します。
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void;
src/services/route-strategy.service.ts
:
import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from '@angular/router';
export class RouteStrategyService implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {};
public static deleteRouteSnapshot(path: string): void {
const name = path.replace(///g, '_');
if (RouteStrategyService.handlers[name]) {
delete RouteStrategyService.handlers[name];
}
}
/**
* 現在のルートをキャッシュする必要があるかどうかを判断する
* このメソッドがfalseを返すと、ルートが変更され、残りのメソッドが呼び出される。
* @param {ActivatedRouteSnapshot} future
* @param {ActivatedRouteSnapshot} curr
* @returns {boolean}
* @memberof CacheRouteReuseStrategy
*/
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig
&& JSON.stringify(future.params) === JSON.stringify(curr.params);
}
/**
* このメソッドは、現在のルートを離れるときに呼び出される。
* trueの場合、ストアメソッドが呼び出される。
* @param {ActivatedRouteSnapshot} route
* @returns {boolean}
* @memberof CacheRouteReuseStrategy
*/
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return true;
}
/**
* キャッシュにルートを書き込む
* ここでは、キャッシュを実装する方法である RouteHandle
* を残してルートを提供する RouteHandle
* @param {ActivatedRouteSnapshot} route
* @param {DetachedRouteHandle} detachedTree
* @memberof CacheRouteReuseStrategy
*/
public store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {
RouteStrategyService.handlers[this.getPath(route)] = detachedTree;
}
/**
* ルートがナビゲートされ、このメソッドがtrueを返す場合は、retrieveメソッドがトリガされる。
* それがfalseを返す場合は、コンポーネントが再作成される
* @param {ActivatedRouteSnapshot} route
* @returns {boolean}
* @memberof CacheRouteReuseStrategy
*/
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!RouteStrategyService.handlers[this.getPath(route)];
}
/**
* キャッシュから読み込むcached route
* 現在のルートのパラメータを提供し、キャッシュを返す RouteHandle
* にキャッシュされたルートを手動でフェッチするために、このメソッドを使うことができる。 RouteHandle
* @param {ActivatedRouteSnapshot} route
* @returns {(DetachedRouteHandle | null)}
* @memberof CacheRouteReuseStrategy
*/
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return RouteStrategyService.handlers[this.getPath(route)]
null;
}
private getPath(route: ActivatedRouteSnapshot): string {
// tslint:disable-next-line: no-string-literal
const path = route['_routerState'].url.replace(///g, '_');
return path;
}
}
src/app/app.module.ts
:
import { RouteReuseStrategy } from '@angular/router';
import { RouteStrategyService } from '../services/route-strategy.service';
@NgModule({
...
providers: [
...
{ provide: RouteReuseStrategy, useClass: RouteStrategyService }
],
bootstrap: [AppComponent]
})
export class AppModule { }
上記の例では、実行時にすべてのルートコンポーネントをキャッシュします。タブの効果を得るには、例えば、タブを閉じて deleteRouteSnapshot メソッドを呼び出し、キャッシュされたページを削除します。
もしこのルートキャッシュをもう使いたくないのであれば、app.module.tsでプロバイダを削除してください!ランニング効果図: