[英]NgRx: CustomRouterStateSerializer serialize() called multiple times
我已經以常見的方式( https://ngrx.io/guide/router-store/configuration )為我的 Angular 項目實現了一個 NgRx Router-Store。
我的“問題”是我的CustomRouterStateSerializer
的序列化方法似乎被多次調用,當通過單擊組件的相應 html 元素觸發 routerLink 時。
您將在StackBlitz上找到以下描述的最小示例應用程序。
我的實現
這是我的router.reducer.ts
文件,其中包含 RouterStateUrl-Interface 和 Serializer-Class:
export interface RouterStateUrl {
url: string;
queryParams: Params;
params: Params;
random: number;
}
export class CustomRouterStateSerializer implements RouterStateSerializer<RouterStateUrl > {
serialize(routerState: RouterStateSnapshot): RouterStateUrl {
const { url, root: { queryParams } } = routerState;
// Random number to be able to match console output to router-state later (with NgRx Store DevTools)
const random = Math.random();
console.warn(`CustomRouterStateSerializer called by ${url}, random: ${random}`);
let state: ActivatedRouteSnapshot = routerState.root;
while(state.firstChild){
state = state.firstChild;
}
const { params } = state;
return {url, queryParams, params, random };
}
}
這是我的app.module.ts
文件:
/*[...]*/
imports: [
/*[...],*/
StoreModule.forRoot(reducers, {
metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true
}
}),
StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.development }),
EffectsModule.forRoot([AppEffects]),
StoreRouterConnectingModule.forRoot({
serializer: CustomRouterStateSerializer,
navigationActionTiming: NavigationActionTiming.PostActivation,
}),
]
/*[...]*/
詳細描述和輸出
假設我的應用程序當前顯示一些項目的概述(url:/projects),並且 routerLink 被觸發以切換組件以顯示作業的概述(url:/jobs)。 控制台將打印三個消息:
CustomRouterStateSerializer called by /projects, random: 0.0896547559010431
CustomRouterStateSerializer called by /jobs, random: 0.7662025752972623
CustomRouterStateSerializer called by /jobs, random: 0.07919176016307328
NgRx Store DevTools 按預期顯示了幾個操作:
@ngrx/router-store/request
router: {
state: {
url: '/projects',
queryParams: {},
params: {},
random: 0.31957045879116797
},
navigationId: 2
}
@ngrx/router-store/navigation
router: {
state: {
url: '/jobs',
queryParams: {},
params: {},
random: 0.7662025752972623
},
navigationId: 3
}
@ngrx/router-store/navigated
router: {
state: {
url: '/jobs',
queryParams: {},
params: {},
random: 0.7662025752972623
},
navigationId: 3
}
如您所見, @ngrx/router-store/navigation
和@ngrx/router-store/navigated
是相同的。 此外,它們的隨機數與第二個控制台輸出相同。 @ngrx/router-store/request
的隨機數屬於舊projects-view的狀態。
NgRx Store DevTools 的輸出似乎符合預期。 但我不明白何時何地調用了其他控制台輸出觸發的序列化方法。 我在任何狀態下都找不到第一個和第三個控制台輸出的任何隨機數。 現在我問自己是否犯了錯誤(實施的東西),或者這是否只是正常行為(但為什么?)。 也許你們中的一些人可以告訴我。
我嘗試了一些東西,但最終它有助於查看@ngrx/router-store
的源代碼。 這個模塊的本質是監聽所有的路由器事件和分派動作。 重要的一段代碼是這個: https : //github.com/ngrx/platform/blob/master/modules/router-store/src/router_store_module.ts#L240-L275
但我不明白何時何地調用了其他控制台輸出觸發的序列化方法。
可以看到這里可以調用serialize()
三種情況:
NavigationStart
(直接)NavigationEnd
(通過dispatchRouterNavigation()
和dispatchRouterNavigated()
方法)RoutesRecognized
(通過dispatchRouterNavigated()
) 這些事件中的每一個都分別調用serialize()
以避免派生狀態:路由器是路由器狀態的來源,它可以在任何給定時間更改。 因此,當需要序列化狀態時,它不會存儲在某處,而是每次都重新計算。 這就是該函數被多次調用的原因。 然而,由於串行器函數應該是純的,這根本不是問題,而是設計的一部分。
我在任何狀態下都找不到第一個和第三個控制台輸出的任何隨機數。
減速器只會在navigation
、 cancel
和error
將路由器狀態放入存儲中——而不是在request
和navigated
。 這意味着,您將在商店中看到的唯一隨機數是源自navigation
操作的隨機數。 所有其他人都只是在“途中”使用。
現在我問自己是否犯了錯誤(實施的東西),或者這是否只是正常行為(但為什么?)。
您的實現看起來不錯,您可以放心了:這是正常的和預期的行為! 🙂 請注意,您的序列化程序函數應該是純的。
希望這可以幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.