blog

RouteReuseStrategyを使用してAngularでコンポーネントをキャッシュする

プロバイダは、Angularのルーティングとコンポーネントのライフサイクルの動作を制御することができます。 コンポーネントを切り替えるとき、Angularは前のコンポーネントを破棄して新しいコンポー...

May 20, 2020 · 5 min. read
シェア

プロバイダを使うと、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でプロバイダを削除してください!

ランニング効果図:





Read next

JVMバイトコードの深い理解

メソッドの Code プロパティには例外テーブルがあり、各例外テーブルのエントリは例外ハンドラを表し、from ポインタ、to ポインタ、ターゲット・ポインタ、および例外をキャッチした型の 4 つの部分で構成されています。これらのポインタの値はバイトコードインデックスで、バイトコードを見つけるために使われます。意味 [from, to) バイトコード範囲、例外型がスローされた場合...

May 20, 2020 · 6 min read