Angular 2의 특정 루트에 대해 RouteReuseStrategy shouldDetach를 구현하는 방법
Angular 2 모듈이 있어 루팅을 구현하고 있으며 탐색 시 상태를 저장해야 합니다.
사용자는 다음을 수행할 수 있어야 합니다.
- '검색 수식'을 사용하여 문서 검색
- 결과 중 하나로 이동하다
- 서버와 통신하지 않고 '검색 결과'로 돌아갑니다.
수 있어요.RouteReuseStrategy
'하다, 하다' 입니다.
문서가 저장되지 않도록 구현하려면 어떻게 해야 합니까?
따라서 경로 "documents" 상태는 저장되어야 하며 경로 "documents/:id" 상태는 저장되지 않아야 합니다.
앤더스, 좋은 질문이야!
저는 당신과 거의 같은 사용 사례를 가지고 있고, 같은 일을 하고 싶었습니다![ User search ]> [ get results ]> [ User navigations ]> [ User navigations back ]> [ BOOM ]의 빠른 결과입니다만, 유저가 네비게이트 한 특정의 결과는 보존하고 싶지 않습니다.
dr;dr
수업을 꼭 해야 합니다.RouteReuseStrategy해 주세요.ngModule되었을 때 [ ]를 shouldDetach★★★★★★★★★★★★★★★★★★★★★★★★★.true합니다., Angular는 경로를 저장합니다.되어 있는 는, .shouldAttach★★★★★★★★★★★★★★★★★시shouldAttachtrue를 반환합니다.Angular는 요청된 경로 대신 저장된 경로를 사용합니다.여기 가지고 놀 수 있는 플런커가 있습니다.
RouteReuse Strategy에 대해서
이 질문을 하면 RouteReuseStrategy를 통해 Angular에게 컴포넌트를 파기하지 않고 나중에 재렌더링하기 위해 저장할 수 있음을 알 수 있습니다.다음과 같은 이점이 있습니다.
- 서버 호출 감소
- 고속화
- 그리고 컴포넌트는 디폴트로 그대로 렌더링됩니다.
예를 들어 사용자가 많은 텍스트를 입력했는데도 페이지를 일시적으로 남기고 싶다면 마지막 항목이 중요합니다.폼의 양이 너무 많기 때문에 엔터프라이즈 어플리케이션에서는 이 기능을 매우 좋아합니다.
이것이 내가 문제를 해결하기 위해 생각해 낸 것이다.말했지만, 이렇게 돼요.RouteReuseStrategy버전 3.4.1 이후에서는 @filename/filename에 의해 제공되고 있습니다.
하기 위해서
먼저 프로젝트에 @angular/router 버전 3.4.1 이상이 있는지 확인합니다.
그런 다음 구현된 클래스를 저장할 파일을 만듭니다.RouteReuseStrategy는 제 거 reuse-strategy.ts을 에에배 the the the에 넣었습니다./app보관을 위한 폴더입니다.현재 이 클래스는 다음과 같습니다.
import { RouteReuseStrategy } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
}
(TypeScript 오류에 대해 걱정하지 마십시오. 이제 곧 모든 문제를 해결할 수 있습니다.)
수강생에게 수업을 제공함으로써 기초 작업을 마칩니다.app.module ''라고 쓰지 해 주세요.CustomReuseStrategy , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,.importreuse-strategy.ts럼에그 한 also도.import { RouteReuseStrategy } from '@angular/router';
@NgModule({
[...],
providers: [
{provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
]
)}
export class AppModule {
}
마지막 부분은 루트의 분리, 저장, 검색 및 재접속 여부를 제어하는 클래스를 작성하는 것입니다.이전 복사/붙여넣기에 앞서, 여기서 기계 구조에 대해 제가 이해하고 있는 대로 간단히 설명하겠습니다.제가 설명하는 방법에 대해서는 아래의 코드를 참조해 주십시오.물론 코드에는 많은 문서가 있습니다.
- 할 는, 「 」
shouldReuseRoute하지만, 이 돌아온다면true그러면 현재 사용 중인 경로가 실제로 재사용되고 다른 메서드는 실행되지 않습니다.거짓 - if
shouldReuseRoutefalse,shouldDetachshouldDetach루트 하고 "경로 저장"을 한다.boolean그만큼을 나타냅니다.여기서 패스를 저장할지 저장하지 않을지를 결정해야 합니다.이 경우 저장할 패스의 배열을 체크합니다.route.routeConfig.pathpath이치노 - if
shouldDetachtrue,store이 경우 루트에 대해 필요한 정보를 저장할 수 있습니다. 일이 있어도 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★DetachedRouteHandleAngular가 나중에 저장된 구성요소를 식별하기 위해 사용하는 것이기 때문입니다.아래에, 나는 두 가지 모두를 저장한다.DetachedRouteHandle및ActivatedRouteSnapshot우리 반의 변수로요
지금까지 스토리지에 대한 논리를 살펴봤지만 구성 요소로 이동하는 것은 어떨까요?Angular는 어떻게 당신의 네비게이션을 가로채고 저장된 네비게이션을 제자리에 두기로 결정합니까?
- 한 번 말하다
shouldReuseRoutefalse,shouldAttach.display 내의 할지 여부를 할 수 입니다. 이것은 컴포넌트를 재생성할지 메모리에서 사용할지 여부를 판단할 수 있는 기회입니다.컴포넌트를 하십시오.true당신 방식대로 잘 지내세요!그리고 넌 잘 가고 있어! - 이제 각 구성 요소를 "우리는 어떤 구성 요소를 사용하시겠습니까?" " 제 포 느 습 니 겠 시 하 용 까 now angular? do"' to will사 want will which indicate you,라고 묻습니다.이 컴포넌트를 반환함으로써 이 컴포넌트를 나타냅니다.
DetachedRouteHandle부에서retrieve.
그게 필요한 논리입니다!이 정도면 충분해!드:의 코드:reuse-strategy.ts아래에는 두 개체를 비교할 수 있는 니프티 함수도 있습니다.할 때 합니다.route.params ★★★★★★★★★★★★★★★★★」route.queryParams저장해 둔 것과 함께요만약 그것들이 모두 일치한다면, 나는 새로운 컴포넌트를 생성하지 않고 저장된 컴포넌트를 사용하고 싶다.하지만 어떻게 하는지는 너에게 달렸어!
reuse-builts.ts를 참조해 주세요.
/**
* reuse-strategy.ts
* by corbfon 1/6/17
*/
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle } from '@angular/router';
/** Interface for object which can store both:
* An ActivatedRouteSnapshot, which is useful for determining whether or not you should attach a route (see this.shouldAttach)
* A DetachedRouteHandle, which is offered up by this.retrieve, in the case that you do want to attach the stored route
*/
interface RouteStorageObject {
snapshot: ActivatedRouteSnapshot;
handle: DetachedRouteHandle;
}
export class CustomReuseStrategy implements RouteReuseStrategy {
/**
* Object which will store RouteStorageObjects indexed by keys
* The keys will all be a path (as in route.routeConfig.path)
* This allows us to see if we've got a route stored for the requested path
*/
storedRoutes: { [key: string]: RouteStorageObject } = {};
/**
* Decides when the route should be stored
* If the route should be stored, I believe the boolean is indicating to a controller whether or not to fire this.store
* _When_ it is called though does not particularly matter, just know that this determines whether or not we store the route
* An idea of what to do here: check the route.routeConfig.path to see if it is a path you would like to store
* @param route This is, at least as I understand it, the route that the user is currently on, and we would like to know if we want to store it
* @returns boolean indicating that we want to (true) or do not want to (false) store that route
*/
shouldDetach(route: ActivatedRouteSnapshot): boolean {
let detach: boolean = true;
console.log("detaching", route, "return: ", detach);
return detach;
}
/**
* Constructs object of type `RouteStorageObject` to store, and then stores it for later attachment
* @param route This is stored for later comparison to requested routes, see `this.shouldAttach`
* @param handle Later to be retrieved by this.retrieve, and offered up to whatever controller is using this class
*/
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
let storedRoute: RouteStorageObject = {
snapshot: route,
handle: handle
};
console.log( "store:", storedRoute, "into: ", this.storedRoutes );
// routes are stored by path - the key is the path name, and the handle is stored under it so that you can only ever have one object stored for a single path
this.storedRoutes[route.routeConfig.path] = storedRoute;
}
/**
* Determines whether or not there is a stored route and, if there is, whether or not it should be rendered in place of requested route
* @param route The route the user requested
* @returns boolean indicating whether or not to render the stored route
*/
shouldAttach(route: ActivatedRouteSnapshot): boolean {
// this will be true if the route has been stored before
let canAttach: boolean = !!route.routeConfig && !!this.storedRoutes[route.routeConfig.path];
// this decides whether the route already stored should be rendered in place of the requested route, and is the return value
// at this point we already know that the paths match because the storedResults key is the route.routeConfig.path
// so, if the route.params and route.queryParams also match, then we should reuse the component
if (canAttach) {
let willAttach: boolean = true;
console.log("param comparison:");
console.log(this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params));
console.log("query param comparison");
console.log(this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams));
let paramsMatch: boolean = this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params);
let queryParamsMatch: boolean = this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams);
console.log("deciding to attach...", route, "does it match?", this.storedRoutes[route.routeConfig.path].snapshot, "return: ", paramsMatch && queryParamsMatch);
return paramsMatch && queryParamsMatch;
} else {
return false;
}
}
/**
* Finds the locally stored instance of the requested route, if it exists, and returns it
* @param route New route the user has requested
* @returns DetachedRouteHandle object which can be used to render the component
*/
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
// return null if the path does not have a routerConfig OR if there is no stored route for that routerConfig
if (!route.routeConfig || !this.storedRoutes[route.routeConfig.path]) return null;
console.log("retrieving", "return: ", this.storedRoutes[route.routeConfig.path]);
/** returns handle when the route.routeConfig.path is already stored */
return this.storedRoutes[route.routeConfig.path].handle;
}
/**
* Determines whether or not the current route should be reused
* @param future The route the user is going to, as triggered by the router
* @param curr The route the user is currently on
* @returns boolean basically indicating true if the user intends to leave the current route
*/
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
console.log("deciding to reuse", "future", future.routeConfig, "current", curr.routeConfig, "return: ", future.routeConfig === curr.routeConfig);
return future.routeConfig === curr.routeConfig;
}
/**
* This nasty bugger finds out whether the objects are _traditionally_ equal to each other, like you might assume someone else would have put this function in vanilla JS already
* One thing to note is that it uses coercive comparison (==) on properties which both objects have, not strict comparison (===)
* Another important note is that the method only tells you if `compare` has all equal parameters to `base`, not the other way around
* @param base The base object which you would like to compare another object to
* @param compare The object to compare to base
* @returns boolean indicating whether or not the objects have all the same properties and those properties are ==
*/
private compareObjects(base: any, compare: any): boolean {
// loop through all properties in base object
for (let baseProperty in base) {
// determine if comparrison object has that property, if not: return false
if (compare.hasOwnProperty(baseProperty)) {
switch(typeof base[baseProperty]) {
// if one is object and other is not: return false
// if they are both objects, recursively call this comparison function
case 'object':
if ( typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty]) ) { return false; } break;
// if one is function and other is not: return false
// if both are functions, compare function.toString() results
case 'function':
if ( typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString() ) { return false; } break;
// otherwise, see if they are equal using coercive comparison
default:
if ( base[baseProperty] != compare[baseProperty] ) { return false; }
}
} else {
return false;
}
}
// returns true only after false HAS NOT BEEN returned through all loops
return true;
}
}
행동
이 실장에서는 사용자가 방문하는 모든 고유 루트가 라우터에 정확히1회 저장됩니다.이렇게 하면 사이트의 사용자 세션 내내 메모리에 저장된 구성 요소가 계속 추가됩니다.그는 '경로 제한'입니다.shouldDetach저장할 경로를 제어합니다.
예
를 들어에서 무언가를 합니다.search/:term 나올 수 www.yourwebsite.com/search/thingsearchedfor검색 페이지에는 다수의 검색 결과가 포함되어 있습니다.이 경로를 저장해야 합니다. 아아아! 결과를 결과를 볼 수 있습니다.view/:resultId보관하고 싶지 않으시겠지만, 아마 한 번만 있을 겁니다.상기의 실장이 실시되고 있는 경우, 저는 단순히,shouldDetach★★★★★★★★★는 다음과 같이 표시됩니다예를 들어 다음과 같습니다.
먼저 저장할 경로를 배열합니다.
private acceptedRoutes: string[] = ["search/:term"];
이제 ,, 제에서shouldDetach 확인해보겠습니다.route.routeConfig.path츠미야
shouldDetach(route: ActivatedRouteSnapshot): boolean {
// check to see if the route's path is in our acceptedRoutes array
if (this.acceptedRoutes.indexOf(route.routeConfig.path) > -1) {
console.log("detaching", route);
return true;
} else {
return false; // will be "view/:resultId" when user navigates to result
}
}
Angular는 루트의 인스턴스를 하나만 저장하므로 이 스토리지는 가볍고 컴포넌트는 다음 위치에만 저장됩니다.search/:term아, 맞다 른든!!!!!!!!!!!!!!!!
기타 링크
아직 많은 문서가 준비되어 있지는 않지만, 현재 존재하는 것에 대한 몇 가지 링크를 다음에 제시하겠습니다.
각도 문서: https://angular.io/docs/ts/latest/api/router/index/RouteReuseStrategy-class.html
도입부 기사: https://www.softwarearchitekt.at/post/2016/12/02/sticky-routes-in-angular-2-3-with-routereusestrategy.aspx
nativescript-discript 기본 RouteReuse Strategy 구현:https://github.com/NativeScript/nativescript-angular/blob/cb4fd3a/nativescript-angular/router/ns-route-reuse-strategy.ts
받아들여진 대답에 주눅들지 마세요. 이것은 꽤 간단합니다.필요한 것에 대한 빠른 답변이 있습니다.저는 최소한 인정된 답을 읽어보라고 권하고 싶습니다. 왜냐하면 그것은 매우 상세한 내용이 담겨있기 때문입니다.
이 솔루션에서는 허가된 답변과 같은 파라미터 비교는 이루어지지 않지만 루트 세트를 저장하는 경우에는 정상적으로 동작합니다.
app.ts.imports:
import { RouteReuseStrategy } from '@angular/router';
import { CustomReuseStrategy, Routing } from './shared/routing';
@NgModule({
//...
providers: [
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy },
]})
shared/syslog.ts:
export class CustomReuseStrategy implements RouteReuseStrategy {
routesToCache: string[] = ["dashboard"];
storedRouteHandles = new Map<string, DetachedRouteHandle>();
// Decides if the route should be stored
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return this.routesToCache.indexOf(route.routeConfig.path) > -1;
}
//Store the information for the route we're destructing
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRouteHandles.set(route.routeConfig.path, handle);
}
//Return true if we have a stored route object for the next route
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRouteHandles.has(route.routeConfig.path);
}
//If we returned true in shouldAttach(), now return the actual route data for restoration
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.storedRouteHandles.get(route.routeConfig.path);
}
//Reuse the route if we're going to and from the same route
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
(Corbfon에 의해) 인정된 답변과 Chris Fremgen의 보다 간단하고 알기 쉬운 설명 외에 재사용 전략을 사용해야 하는 보다 유연한 경로 처리 방법을 추가하고 싶습니다.
두 응답 모두 캐시할 경로를 배열에 저장한 후 현재 경로 경로가 배열에 있는지 여부를 확인합니다.은 하다, 하다, 하다, 하다에서 합니다.shouldDetach★★★★★★ 。
입니다.루트 이름을 변경하려면 루트 이름도 변경해야 하기 때문입니다.CustomReuseStrategyclass. 개발자가 루트 할 수 .RouteReuseStrategy.
에 수 .RouterModule를 사용합니다.data이렇게 하면 루트 이름을 변경해도 재사용 전략이 적용됩니다.
{
path: 'route-name-i-can-change',
component: TestComponent,
data: {
reuseRoute: true
}
}
에 리 and and에shouldDetach그 방법을 활용할 수 있습니다.
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute === true;
}
보다 유효하고 완전하며 재사용 가능한 또 다른 구현입니다.이것은 @U'ur Dincs로서 저속 로드된 모듈을 지원하며 @Davor 루트 데이터 플래그를 통합합니다.가장 향상된 기능은 페이지 절대 경로를 기반으로 (거의) 고유 식별자를 자동으로 생성하는 것입니다.이렇게 하면 모든 페이지에서 직접 정의할 필요가 없습니다.
의 페이지를 마크합니다. " " " " "reuseRoute: true . . . . 。shouldDetach★★★★★★ 。
{
path: '',
component: MyPageComponent,
data: { reuseRoute: true },
}
이는 쿼리 매개 변수를 비교하지 않고 가장 간단한 전략 구현입니다.
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'
export class CustomReuseStrategy implements RouteReuseStrategy {
storedHandles: { [key: string]: DetachedRouteHandle } = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute || false;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const id = this.createIdentifier(route);
if (route.data.reuseRoute) {
this.storedHandles[id] = handle;
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const id = this.createIdentifier(route);
const handle = this.storedHandles[id];
const canAttach = !!route.routeConfig && !!handle;
return canAttach;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const id = this.createIdentifier(route);
if (!route.routeConfig || !this.storedHandles[id]) return null;
return this.storedHandles[id];
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
private createIdentifier(route: ActivatedRouteSnapshot) {
// Build the complete path from the root to the input route
const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
// Result: ${route_depth}-${path}
return segments.length + '-' + subpaths.join('/');
}
}
이치 compareObjects@Corbfon @Corbfon cor보다 다다 다다 다cor corcor corcor 。기본 및 비교 오브젝트의 속성을 모두 루프합니다. lodash와 같은 높은 할 수 .isEqual★★★★★★ 。
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'
interface RouteStorageObject {
snapshot: ActivatedRouteSnapshot;
handle: DetachedRouteHandle;
}
export class CustomReuseStrategy implements RouteReuseStrategy {
storedRoutes: { [key: string]: RouteStorageObject } = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute || false;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const id = this.createIdentifier(route);
if (route.data.reuseRoute && id.length > 0) {
this.storedRoutes[id] = { handle, snapshot: route };
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const id = this.createIdentifier(route);
const storedObject = this.storedRoutes[id];
const canAttach = !!route.routeConfig && !!storedObject;
if (!canAttach) return false;
const paramsMatch = this.compareObjects(route.params, storedObject.snapshot.params);
const queryParamsMatch = this.compareObjects(route.queryParams, storedObject.snapshot.queryParams);
console.log('deciding to attach...', route, 'does it match?');
console.log('param comparison:', paramsMatch);
console.log('query param comparison', queryParamsMatch);
console.log(storedObject.snapshot, 'return: ', paramsMatch && queryParamsMatch);
return paramsMatch && queryParamsMatch;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const id = this.createIdentifier(route);
if (!route.routeConfig || !this.storedRoutes[id]) return null;
return this.storedRoutes[id].handle;
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
private createIdentifier(route: ActivatedRouteSnapshot) {
// Build the complete path from the root to the input route
const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
// Result: ${route_depth}-${path}
return segments.length + '-' + subpaths.join('/');
}
private compareObjects(base: any, compare: any): boolean {
// loop through all properties
for (const baseProperty in { ...base, ...compare }) {
// determine if comparrison object has that property, if not: return false
if (compare.hasOwnProperty(baseProperty)) {
switch (typeof base[baseProperty]) {
// if one is object and other is not: return false
// if they are both objects, recursively call this comparison function
case 'object':
if (typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty])) {
return false;
}
break;
// if one is function and other is not: return false
// if both are functions, compare function.toString() results
case 'function':
if (typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString()) {
return false;
}
break;
// otherwise, see if they are equal using coercive comparison
default:
// tslint:disable-next-line triple-equals
if (base[baseProperty] != compare[baseProperty]) {
return false;
}
}
} else {
return false;
}
}
// returns true only after false HAS NOT BEEN returned through all loops
return true;
}
}
내 답변에 대한 코멘트를 남길 수 있는 가장 좋은 키를 생성하는 방법이 있다면 코드를 업데이트하겠습니다.
솔루션을 공유해 주신 모든 분들께 감사드립니다.
Chris Fremgen의 전략을 장해가 적은 모듈에서 사용하려면 CustomReuseStrategy 클래스를 다음과 같이 변경합니다.
import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
routesToCache: string[] = ["company"];
storedRouteHandles = new Map<string, DetachedRouteHandle>();
// Decides if the route should be stored
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return this.routesToCache.indexOf(route.data["key"]) > -1;
}
//Store the information for the route we're destructing
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRouteHandles.set(route.data["key"], handle);
}
//Return true if we have a stored route object for the next route
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRouteHandles.has(route.data["key"]);
}
//If we returned true in shouldAttach(), now return the actual route data for restoration
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.storedRouteHandles.get(route.data["key"]);
}
//Reuse the route if we're going to and from the same route
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
마지막으로 기능 모듈의 라우팅 파일에서 키를 정의합니다.
{ path: '', component: CompanyComponent, children: [
{path: '', component: CompanyListComponent, data: {key: "company"}},
{path: ':companyID', component: CompanyDetailComponent},
]}
자세한 것은 이쪽.
Angular 13 (28/02/2022 버전)
많은 가이드와 제안을 읽은 후에.이건 설명할 수 있어요
첫째, 당신은 미래와 미래를 이해해야 한다.
에서 : " " " 에서 네비게이트 합니다.localhost/a로로 합니다.localhost/b제학학 【b】
1: ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★/a -> /b
- willReuseRoute:
falsefuture !== current. - Detach : :: :
truedetach) 것 ( ) 。store.attach를 참조해 주세요. - " " " " 。
true || fasehandler그렇다면attach하지 No」(이 는 「NoNo」)
2: ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」/b?id=1 -> /b?id=2
- willReuseRoute:
truefuture === current; - should Detach: 건너뛰기
- should Retrieve: 건너뛰기
3: "에서 " 3: "에서 "/b -> /a
- willReuseRoute:
falsefuture !== current. - Detach : :: :
truedetach) 것 ( ) 。store.attach를 참조해 주세요. - " " " " 。
true || fasehandler그렇다면attach하지 '그렇다' (이 경우는 '네'입니다.
https://stackoverflow.com/a/45788698/5748537 에서 보다 심플한 비주얼을 보실 수 있습니다.
navigate to a
shouldReuseRoute->return true->do nothing
a->b
shouldReuseRoute()->return false->shouldDetach()->return true->store a
then b->a
shouldReuseRoute()->return false->shouldDetach()->return true->store b->retrieve() return a ->attach() a.
https://stackoverflow.com/a/69004775/5748537에서 훨씬 더 시각적으로 확인할 수 있습니다.
그리고 각 팀의 올바른 코드를 완성합니다.https://github.com/angular/angular/issues/44383
export class CustomRouteReuseStrategy implements RouteReuseStrategy {
private handlers: Map<Route, DetachedRouteHandle> = new Map();
constructor() {}
public shouldDetach(_route: ActivatedRouteSnapshot): boolean {
return true;
}
public store(
route: ActivatedRouteSnapshot,
handle: DetachedRouteHandle
): void {
if (!route.routeConfig) return;
this.handlers.set(route.routeConfig, handle);
}
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!route.routeConfig && !!this.handlers.get(route.routeConfig);
}
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null {
if (!route.routeConfig || !this.handlers.has(route.routeConfig)) return null;
return this.handlers.get(route.routeConfig)!;
}
public shouldReuseRoute(
future: ActivatedRouteSnapshot,
curr: ActivatedRouteSnapshot
): boolean {
return future.routeConfig === curr.routeConfig;
}
}
우리의 경우 언급된 모든 해결 방법이 다소 불충분했다.다음과 같은 기능을 갖춘 소규모 비즈니스 앱이 있습니다.
- 소개 페이지
- 로그인 페이지
- 앱(로그인 후)
델의 요건:
- 느리게 로드된 모듈
- 멀티 레벨 루트
- 모든 라우터/컴포넌트 상태를 앱 섹션의 메모리에 저장
- 특정 경로에서 기본 각도 재사용 전략을 사용하는 옵션
- 로그아웃 시 메모리에 저장된 모든 구성 요소 삭제
루트의 간단한 예:
const routes: Routes = [{
path: '',
children: [
{
path: '',
canActivate: [CanActivate],
loadChildren: () => import('./modules/dashboard/dashboard.module').then(module => module.DashboardModule)
},
{
path: 'companies',
canActivate: [CanActivate],
loadChildren: () => import('./modules/company/company.module').then(module => module.CompanyModule)
}
]
},
{
path: 'login',
loadChildren: () => import('./modules/login/login.module').then(module => module.LoginModule),
data: {
defaultReuseStrategy: true, // Ignore our custom route strategy
resetReuseStrategy: true // Logout redirect user to login and all data are destroyed
}
}];
재사용 전략:
export class AppReuseStrategy implements RouteReuseStrategy {
private handles: Map<string, DetachedRouteHandle> = new Map();
// Asks if a snapshot from the current routing can be used for the future routing.
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
// Asks if a snapshot for the current route already has been stored.
// Return true, if handles map contains the right snapshot and the router should re-attach this snapshot to the routing.
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
if (this.shouldResetReuseStrategy(route)) {
this.deactivateAllHandles();
return false;
}
if (this.shouldIgnoreReuseStrategy(route)) {
return false;
}
return this.handles.has(this.getKey(route));
}
// Load the snapshot from storage. It's only called, if the shouldAttach-method returned true.
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return this.handles.get(this.getKey(route)) || null;
}
// Asks if the snapshot should be detached from the router.
// That means that the router will no longer handle this snapshot after it has been stored by calling the store-method.
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return !this.shouldIgnoreReuseStrategy(route);
}
// After the router has asked by using the shouldDetach-method and it returned true, the store-method is called (not immediately but some time later).
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
if (!handle) {
return;
}
this.handles.set(this.getKey(route), handle);
}
private shouldResetReuseStrategy(route: ActivatedRouteSnapshot): boolean {
let snapshot: ActivatedRouteSnapshot = route;
while (snapshot.children && snapshot.children.length) {
snapshot = snapshot.children[0];
}
return snapshot.data && snapshot.data.resetReuseStrategy;
}
private shouldIgnoreReuseStrategy(route: ActivatedRouteSnapshot): boolean {
return route.data && route.data.defaultReuseStrategy;
}
private deactivateAllHandles(): void {
this.handles.forEach((handle: DetachedRouteHandle) => this.destroyComponent(handle));
this.handles.clear();
}
private destroyComponent(handle: DetachedRouteHandle): void {
const componentRef: ComponentRef<any> = handle['componentRef'];
if (componentRef) {
componentRef.destroy();
}
}
private getKey(route: ActivatedRouteSnapshot): string {
return route.pathFromRoot
.map((snapshot: ActivatedRouteSnapshot) => snapshot.routeConfig ? snapshot.routeConfig.path : '')
.filter((path: string) => path.length > 0)
.join('');
}
}
다음은 work! 레퍼런스:https://www.cnblogs.com/lovesangel/p/7853364.html
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {}
private static waitDelete: string
public static deleteRouteSnapshot(name: string): void {
if (CustomReuseStrategy.handlers[name]) {
delete CustomReuseStrategy.handlers[name];
} else {
CustomReuseStrategy.waitDelete = name;
}
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return true;
}
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
if (CustomReuseStrategy.waitDelete && CustomReuseStrategy.waitDelete == this.getRouteUrl(route)) {
// 如果待删除是当前路由则不存储快照
CustomReuseStrategy.waitDelete = null
return;
}
CustomReuseStrategy.handlers[this.getRouteUrl(route)] = handle
}
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!CustomReuseStrategy.handlers[this.getRouteUrl(route)]
}
/** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null
}
return CustomReuseStrategy.handlers[this.getRouteUrl(route)]
}
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params);
}
private getRouteUrl(route: ActivatedRouteSnapshot) {
return route['_routerState'].url.replace(/\//g, '_')
}
}
커스텀 루트 재사용 전략의 실장에서는, 다음의 문제에 직면했습니다.
- 루트 부가/분리 작업: 서브스크립션 관리, 청소 등
- 마지막 파라미터화된 경로 상태(메모리 최적화)만 유지합니다.
- 상태가 아닌 컴포넌트를 재사용: 상태 관리 도구를 사용하여 상태를 관리합니다.
- "다른 경로에서 생성된 ActivatedRouteSnapshot을 재접속할 수 없습니다" 오류입니다.
그래서 나는 이런 문제들을 해결하는 도서관을 썼다.라이브러리는 연결/분리 후크를 위한 서비스와 데코레이터를 제공하며 경로의 경로가 아닌 분리된 경로를 저장하기 위해 경로의 구성요소를 사용합니다.
예:
/* Usage with decorators */
@onAttach()
public onAttach(): void {
// your code...
}
@onDetach()
public onDetach(): void {
// your code...
}
/* Usage with a service */
public ngOnInit(): void {
this.cacheRouteReuse
.onAttach(HomeComponent) // or any route's component
.subscribe(component => {
// your code...
});
this.cacheRouteReuse
.onDetach(HomeComponent) // or any route's component
.subscribe(component => {
// your code...
});
}
라이브러리: https://www.npmjs.com/package/ng-cache-route-reuse
위의 답변은 모두 훌륭하지만 라우터가 저속하고 너무 네스트되어 있는 경우 모두 정상적으로 동작하지 않습니다.
하기 위해 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」shouldReuseRoute해야 합니다.
Path A: abc/xyx/3
Path B: abc/rty/8
<abc>
<router-outlet></router-outlet>
</abc>
/* If we move from pathA to pathB or vice versa,
* then `routeConfig` will be same since we are routing within the same abc,
* but to store the handle properly, you should store fullPath as key.
*/
shouldReuseRoute(
future: ActivatedRouteSnapshot,
curr: ActivatedRouteSnapshot
): boolean {
return future.routeConfig === curr.routeConfig;
}
private getPathFromRoot(route: ActivatedRouteSnapshot) {
return (route["_urlSegment"]["segments"] as UrlSegment[])
.map((seg) => seg.path)
.join("/");
}
언급URL : https://stackoverflow.com/questions/41280471/how-to-implement-routereusestrategy-shoulddetach-for-specific-routes-in-angular
'programing' 카테고리의 다른 글
| 자체 참조 테이블(Oracle)에 대한 SQL 재귀 쿼리 (0) | 2023.03.05 |
|---|---|
| Angularjs - 현재 날짜 표시 (0) | 2023.03.05 |
| 농담 모의 반응 컨텍스트 (0) | 2023.03.05 |
| 문자열을 int64 유형의 Go 값으로 이동 해제할 수 없습니다. (0) | 2023.03.05 |
| redex 툴킷에서 리듀서와 엑스트라 리듀서의 차이점은 무엇입니까? (0) | 2023.03.05 |