It's common practice in angular space to cache reused components with the help of RouteReuseStrategy
:
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
DetachedRouteHandle,
Route,
RouteReuseStrategy,
} from '@angular/router';
@Injectable()
export class CustomReuseStrategy extends RouteReuseStrategy {
private pool = new WeakMap<Route, DetachedRouteHandle>();
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!this.pool.get(route.routeConfig);
}
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return this.pool.get(route.routeConfig);
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return (
route.routeConfig.data?.shouldReuse && !this.pool.get(route.routeConfig)
);
}
public store(
route: ActivatedRouteSnapshot,
handle: DetachedRouteHandle | null
) {
this.pool.set(route.routeConfig, handle);
}
public shouldReuseRoute(
future: ActivatedRouteSnapshot,
curr: ActivatedRouteSnapshot
): boolean {
return future.routeConfig === curr.routeConfig;
}
}
then new CustomReuseStrategy
should be provided to the module:
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ChildComponent } from './child/child.component';
import { CustomReuseStrategy } from './route-reuse-strategy';
import { NgModule } from '@angular/core';
import { RouteReuseStrategy, RouterModule } from '@angular/router';
@NgModule({
imports: [
...
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomReuseStrategy,
},
],
})
export class AppModule {}
at this point angular router module registers the new strategy to reuse routes (from cache) and the instance of the strategy is available under Router#routeReuseStrategy
.
Letβs define few routes to demonstrate the new RouterOutlet
events (/c
marked to reuse on the next activation):
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { RouteReuseStrategy, RouterModule } from '@angular/router';
import { ChildComponent } from './child/child.component';
import { CustomReuseStrategy } from './route-reuse-strategy';
@NgModule({
imports: [
RouterModule.forRoot([
{
path: 'a',
component: ChildComponent,
},
{
path: 'b',
component: ChildComponent,
},
{
path: 'c',
component: ChildComponent,
data: {
shouldReuse: true,
},
},
]),
BrowserModule,
],
declarations: [AppComponent, ChildComponent],
bootstrap: [AppComponent],
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomReuseStrategy,
},
],
})
export class AppModule {}
and the app.component.html
looks like (just a few links and the router-outlet
with new attach
/detach
events):
<a routerLink="/a">navigate to /a</a> <br />
<a routerLink="/b">navigate to /b</a> <br />
<a routerLink="/c">navigate to /c</a> <br />
<router-outlet
(activate)="onActivate($event)"
(deactivate)="onDeactivate($event)"
(attach)="onAttach($event)" <--- the new event
(detach)="onDetach($event)" <--- the new event
></router-outlet>
An attach
event emits every time when the RouteReuseStrategy
instructs the outlet to reattach the subtree, and the detach
event emits when the RouteReuseStrategy
instructs the outlet to detach the subtree. So attach
event will be emitted on the next re-navigation to the /c
url instead of activate
one, because the component was attached from cache and not instantiated.
Sources:
- All of the described code is available on StackBlitz (unfortunately angular 13 is not available yet on StackBlitz): https://stackblitz.com/edit/new-router-outlets-events?file=src/app/app.component.html
- Angular commit: https://github.com/angular/angular/commit/4f3beffdbfa974b380b2225f163d363dd17e10bd
Top comments (0)