
Прежде чем перейти к стратегии повторного использования маршрута, давайте разберемся, что произойдет, если мы перейдем от одного компонента к другому, изменив маршрут.
Допустим, вы находитесь на пути /compA и загрузили компонент A в DOM, и теперь, когда вы измените маршрут на /compB, который загрузит компонент B,
- компонент A будет уничтожен, что означает, что он будет удален из DOM, и его соответствующий экземпляр компонента также будет удален, (мы можем проверить это, проверив, вызывается ли хук
ngOnDestroyили нет ). - компонент B будет заново инициализирован и отрендерен в DOM(мы можем проверить это, проверив, вызывается ли хук
ngOnInit).
Теперь снова, если мы попытаемся перейти от компонента Bк компоненту A, описанный выше процесс повторится (компонент Bбудет уничтожен, и компонент A будет инициализирован).
Мы можем завершить поведение по умолчанию, сказав:если мы перейдем от одного компонента к другому с помощью средств маршрутизации, текущий компонент будет уничтожен, а новый компонент будет инициализирован, это будет происходить каждый раз, когда мы переключаемся от одного компонента к другому компоненту.
Проблема
Инициализация и уничтожение компонента — довольно дорогостоящий процесс, потому что весь JavaScript должен быть выполнен снова, и DOM должен быть отрендерен снова.
Это может постепенно привести к ухудшению производительности, если размер компонента большой.
Решение
При переходе к другому компоненту, вместо уничтожения текущего компонента, что, если мы сможем сохранить компонент где-нибудь и повторно использовать его при повторном обращении к нему?
Возможно ли это?
Да, мы можем сделать это, используя Angular Стратегии повторного использования маршрута
Что такое стратегия повторного использования маршрута?
Это способ, которым Angular обеспечивает повышение производительности при переходе с одного маршрута на другой, выполняя следующие действия:
- Вместо того, чтобы уничтожать компонент, сохраните экземпляр компонента где-нибудь.
- При повторном доступе к тому же маршруту повторно используйте сохраненный экземпляр компонента вместо создания нового.
Поведение по умолчанию
Angular по умолчанию не будет хранить и повторно использовать какие-либо экземпляры компонентов, если вы не попытаетесь перейти к тому же маршруту, по которому вы сейчас находитесь.
Таким образом, это означает, что каждый раз angular будет уничтожать компонент и воссоздавать его снова при повторном посещении.
Мы можем переопределить это поведение по умолчанию, внедрив собственную RouteReuseStrategy.
Как реализовать собственную стратегию RouteReuseStrategy?
Для этого нам нужно предоставить наш собственный класс в качестве значения существующего класса RouteReuseStrategy, который содержит поведение angular по умолчанию.
Прежде чем перейти к конкретным шагам, давайте разберемся с методами RouteReuseStrategy, которые определяют, как повторно использовать компонент.
Существует пять методов, которые будут вызываться один за другим в определенном порядке при любом изменении пути маршрутизации.
1. следует отсоединить
@param1 — ActivatedRouteSnapshot
returnType-boolean
- Это будет вызываться первым при переходе с одного маршрута на другой, чтобы определить, можно ли отсоединить компонент (сохранить вместо его уничтожения) для повторного использования.
- Мы можем получить доступ к сведениям о маршруте, используя параметр
ActivatedRouteSnapshot, и мы можем вернутьtrue, если мы хотим отсоединиться, или вернутьfalse.
2. хранить
@param1 — ActivatedRouteSnapshot , @param2 — DetachedRouteHandle ,
returnType-boolean
- Когда
shouldDetachвозвращаетtrue, это означает, что этот метод будет вызван, и здесь у нас может быть собственная логика для хранения где-то экземпляра компонента. - Мы можем получить сведения о текущем маршруте из параметра
ActivatedRouteSnapshot, а экземпляр его компонента — изDetachedRouteHandle. - Как мы сохраняем, полностью зависит от нас, мы можем сохранить его в объекте, карте, сервисе или чем-то еще, (мы должны иметь возможность получить сохраненное значение в другом методе с именем
retrieve, который мы увидим ниже) - Путь маршрута и соответствующий экземпляр компонента (
DetachedRouteHandle) рекомендуется хранить в паре ключ-значение, чтобы при необходимости их можно было легко получить.
Оба вышеупомянутых метода предназначены для работы с компонентом, от которого мы уходим, все дело в том, чтобы вместо его уничтожения сохранить его где-нибудь.
Следующие два метода, которые мы рассмотрим, связаны с компонентом, который мы пытаемся загрузить, вместо его повторного создания, извлечения из места, где он был сохранен, и повторного использования
3. следует прикрепить
@param1 — ActivatedRouteSnapshot
returnType-boolean
- Этот метод используется для определения того, следует ли повторно использовать компонент, который мы пытаемся загрузить (вместо того, чтобы создавать его заново) или нет.
- Верните
true, если мы хотим повторно использовать, или вернитеfalse.
4. получить
@param1 — ActivatedRouteSnapshot
returnType-DetachedRouteHandle
- Когда
shouldAttachвозвращаетtrueозначает, что этот метод будет вызван, и здесь нам нужно получить и вернуть экземпляр компонента (DetachedRouteHandle), который мы сохранили в методеstore()для этого путь маршрута (мы можем получить доступ к пути, используяActivatedRouteSnapshotparam.
5. следует повторно использовать маршрут
- Этот метод используется для определения того, следует ли повторно использовать маршрут или нет.
- Это должно вернуть
true, чтобы заставить работать как стратегию Angular по умолчанию, так и нашу собственную стратегию.
Давайте создадим нашу собственную стратегию повторного использования маршрута для нашего приложения, где мы настроили маршрутизацию /compA и /compB для загрузки компонентов component A и component B соответственно.
По умолчанию навигация между этими компонентами уничтожит текущий компонент, в котором мы находимся, и инициализирует новый компонент, который мы пытаемся загрузить.
Мы реализуем нашу RouteReuseStrategy таким образом, чтобы оба компонента использовались повторно.
Шаг 1. Создайте новый класс, реализуя RouteReuseStrategyабстрактный класс.
RouteReuseStrategy— это абстрактный класс, в котором будут объявлены все методы конфигурации, которые мы обсуждали выше, поэтому нам нужно определить эти методы в новом классе, который мы создаем.
Шаг 2. Определите метод shouldDetach
- Нам нужно вернуть
trueздесь, если путь маршрутаcompAилиcompB, чтобы этот компонент не был уничтожен при выходе.
shouldDetach(route: ActivatedRouteSnapshot): boolean {
const path = route.routeConfig.path;
return path && ['compA', 'compB'].includes(path);
}
Шаг 3.определение метода store
- Нам нужно сохранить экземпляр компонента в виде
DetachedRouteHandleдля повторного использования.
private routeStore = new Map<string, DetachedRouteHandle>();
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.routeStore.set(route.routeConfig.path, handle);
}
Шаг 4: определите метод shouldAttach
- Нам нужно вернуть
true, если путь маршрута равенcompAилиcompBи в нашем routerStore есть любое значениеDetachedRouteHandleдля этого пути маршрута.
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const path = route.routeConfig.path;
return (
path && ['compA', 'compB'].includes(path) && !!this.routeStore.get(path)
);
}
Шаг 5: определите метод retrive
- Нам нужно вернуть
DetachedRouteHandle, который мы сохранили для этого пути маршрута в методеstore().
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const path = route.routeConfig.path;
return this.routeStore.get(path);
}
Шаг 6: определите метод shouldReuseRoute
- Этот метод используется для определения того, следует ли повторно использовать маршруты или нет, он будет вызываться при каждом изменении маршрута, если мы попытаемся перейти к тому же компоненту, в котором мы сейчас находимся, он будет использоваться повторно.
curr— маршрут, с которого мы уходим,future— маршрут, на который пытаемся перейти
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
Теперь мы закончили с определением методов в нашем классе, наш код будет выглядеть так:
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;
}
}
Шаг 7. Предоставьте нашему классу значение по умолчанию RouteReuseStrategy
- После всех настроек нам нужно указать Angular использовать этот класс в качестве значения, чтобы определить, как повторно использовать маршрутизацию. мы можем сделать это, зарегистрировав этот класс в массиве провайдера как значение существующего класса
RouteReuseStrategyпо умолчанию Angular:
// app.module.ts
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomRouteReuseStrategy,
},
],
Вот и все, теперь мы реализовали собственную стратегию повторного использования маршрута для нашего приложения.
Посмотрите приведенный ниже GIF, чтобы понять поведение маршрутизации до и после реализации RouteReuseStrategy.

Посмотрите живой пример здесь, на stackblitz.
⚠️ Примечание.
Если мы передаем какие-либо данные по маршруту с использованием средств queryParams или params, нам нужно написать пользовательскую логику внутри метода shouldAttach, чтобы проверить, присутствуют ли params или queryParams в сохраненном маршрут и текущий маршрут совпадают или нет, если оба path и params одинаковы, то нам нужно вернуть только true.
Спасибо за прочтение, надеюсь, эта статья поможет вам хоть как-то обогатить свои знания.
Подпишитесь на меня в Linkedin и Medium, чтобы узнать больше такого контента.
Продолжайте учиться и продолжайте программировать!
Создавайте приложения с повторно используемыми компонентами, такими как Lego.

Инструмент с открытым исходным кодом Bit помогает более чем 250 000 разработчиков создавать приложения с компонентами.
Превратите любой пользовательский интерфейс, функцию или страницу в компонент многократного использования — и поделитесь им со своими приложениями. Легче сотрудничать и строить быстрее.
Разделите приложения на компоненты, чтобы упростить разработку приложений, и наслаждайтесь наилучшими возможностями для рабочих процессов, которые вы хотите: