0

How to Build a Route Reuse Strategy with Angular

 1 year ago
source link: https://blog.bitsrc.io/angular-route-reuse-strategy-c7939ebbf797
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to Build a Route Reuse Strategy with Angular

1*dzZBeaU9dfsXrFfekHV-WA.png

Before jumping into Route Reuse Strategy, Let’s understand what will happen if we navigate from one component to another component by changing the route.

Let’s say you are in the path /compA and which has loaded component A in the DOM, and now when you change the route to /compB which will load component B,

  • component A will be destroyed, which means it will be removed from the DOM and its respective component instance also will be removed,( we can verify it by checking whether the ngOnDestroy hook is called or not).
  • component B will be initialized freshly and it will be rendered in DOM ( we can verify it by checking whether the ngOnInit hook is called or not).

Now again if we try to navigate from component B to component A means, the above process will happen again (component B will be destroyed, and component A will be initialized).

We can conclude the default behavior by sayingif we navigate from one component to another component via routing means, the current component will be destroyed and the new component will be initialized, this will happen every time when we switch from one component to another component.

The Problem

Initializing & destroying a component is quite an expensive process because the whole JavaScript needs to be executed again and the DOM has to be rendered again.

This may gradually lead to poor performance if the component size is large.

The Solution

While navigating to another component, instead of destroying the current component, What if we can store the component somewhere and reuse it when it is accessed again?

Is it possible?
Yes
, we can do it using Angular Route Reuse Strategies

What is Route Reuse Strategy?

It is the way Angular provides to improve performance while leaving from any route to another by doing the following things:

  • Instead of destroying the component, store the component instance somewhere.
  • If the same route is accessed again, re-use the stored instance of the component instead of creating a new one.

Default behavior

Angular by default will not store any component instance and re-use unless you try to navigate to the same route that you are currently in.

So this means, every time angular will destroy the component and recreate it again when visited again.

We can override this default behavior by implementing our own RouteReuseStrategy.

How to implement our own RouteReuseStrategy?

To achieve this, we need to provide our own class as a value to the existing RouteReuseStrategy class which contains angular default behavior.

Before jumping into actual steps, let’s understand the methods of RouteReuseStrategy which will define how to re-use the component.

There are five methods that will be called one by one in a particular order when any change in the routing path happens.

1. shouldDetach

@param1 — ActivatedRouteSnapshot
returnType-boolean

  • This will be called first while leaving from one route to another to determine whether the component can be detached ( stored instead of destroying it) for re-use.
  • We can access the route details using the ActivatedRouteSnapshotparam and we can return true if we want to detach, or else return false.

2. store

@param1 — ActivatedRouteSnapshot , @param2 — DetachedRouteHandle ,
returnType-boolean

  • When shouldDetach returned true means, this method will be called and here we can have our own logic to store the component instance somewhere.
  • We can get the current route details from the ActivatedRouteSnapshotparam and its component instance from DetachedRouteHandle.
  • How we are storing is totally up to us, we can store it in the object, Map, service, or something else, ( we should be able to fetch the stored value in another method called retrieve which we are going to see below)
  • It is recommended to store the route path and its respective component instance(DetachedRouteHandle) in a key-value pair so that it will be easy to retrieve it when required.

Both the above methods are to deal with the component from which we are leaving, it is all about instead of destroying it, store it somewhere.

The next two methods we are going to see are about the component which we are trying to load, it is all about instead of re-creating it, retrieve it from the place it was stored and re-use it

3. shouldAttach

@param1 — ActivatedRouteSnapshot
returnType-boolean

  • This method is used to determine whether the component that we are trying to load should be re-used ( instead of creating it newly) or not
  • Return true if we want to re-use the or else return false.

4. retrieve

@param1 — ActivatedRouteSnapshot
returnType-DetachedRouteHandle

  • When shouldAttach returns true means, this method will be called, and here we need to retrieve and return the component instance (DetachedRouteHandle) which we have stored in the store() method for this route path ( we can access the path using ActivatedRouteSnapshotparam.

5. shouldReuseRoute

  • This method is used to determine whether the route should be re-used or not.
  • This must return true, in order to make both the Angular default strategy and our own strategy work.

Let’s create our own route reuse strategy for our application where we have configured our routing /compA and /compB to load the components component A and component B respectively.

By default, navigating between these components will destroy the current component that we are in and initialize the new component that we try to load.

We will implement our RouteReuseStrategy in a way that both components will be reused.

Step 1: Create a new class by implementing the RouteReuseStrategyabstract class

  • RouteReuseStrategyis an abstract class where all the configuration methods that we discussed above will be declared, so we need to define those methods in the new class that we are creating.

Step 2: Define the shouldDetach method

  • We need to return true here if the route path is either compA or compB, so that component will not be destroyed while leaving.
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
const path = route.routeConfig.path;
return path && ['compA', 'compB'].includes(path);
}

Step 3: define the store method

  • We need to store the component instance in the form of DetachedRouteHandle for reuse
private routeStore = new Map<string, DetachedRouteHandle>();

store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.routeStore.set(route.routeConfig.path, handle);
}

Step 4: define the shouldAttach method

  • We need to return true if the route path is either compA or compB and our routerStore has any DetachedRouteHandle value for this route path.
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
const path = route.routeConfig.path;
return (
path && ['compA', 'compB'].includes(path) && !!this.routeStore.get(path)
);
}

Step 5: define the retrieve method

  • We need to return the DetachedRouteHandle that we stored for this route path in the store() method.
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const path = route.routeConfig.path;
return this.routeStore.get(path);
}

Step 6: define the shouldReuseRoute method

  • This method is used to determine whether to reuse the routes or not, it will be called for every route change, if we try to navigate to the same component that we are currently in means, it will be re-used.
  • curr — route from which we are leaving,
    future — route to which we are trying to navigate
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}

Now we are done with defining the methods in our class, our code will look like this:

import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy,} from '@angular/router';

export class CustomRouteReuseStrategy implements RouteReuseStrategy {
private routeStore = new Map<string, DetachedRouteHandle>();

shouldDetach(route: ActivatedRouteSnapshot): boolean {
const path = route.routeConfig.path;
return path && ['compA', 'compB'].includes(path);
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.routeStore.set(route.routeConfig.path, handle);
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const path = route.routeConfig.path;
return (
path && ['compA', 'compB'].includes(path) && !!this.routeStore.get(path)
);
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const path = route.routeConfig.path;
return this.routeStore.get(path);
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}

Step 7: Provide our class as a value to default RouteReuseStrategy

  • After configuring everything, we need to tell Angular to use this class as a value to determine how to reuse the routing. we can do it by registering this class in the provider’s array as a value to existing Angular’s default RouteReuseStrategy class:
// app.module.ts  
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomRouteReuseStrategy,
},
],

That’s all, now we have implemented our own route reuse strategy for our application.

Check the below GIF to understand the routing behavior before and after implementing RouteReuseStrategy

1*rvGoAcN1VTEN5NlYbQ489Q.gif
GIF to demonstrate the Default & RouteReuseStrategy routing behavior

Check the live example here at stackblitz.

⚠️ Note:
If we pass any data through the route using queryParams or params means, we need to write a custom logic inside the shouldAttach method to check whether the params or queryParams present in the stored route and current route are the same or not, if both path and params are same, then only we need to return true.

Thanks for reading, I hope this article helps you in some way to enrich your knowledge.

Follow me on Linkedin and Medium for more such content.

Keep learning and keep coding!

Build apps with reusable components like Lego

1*mutURvkHDCCgCzhHe-lC5Q.png

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK