我已经以通用方式(https://ngrx.io/guide/router-store/configuration)为Angular项目实现了NgRx路由器存储。
我的“问题”是,当我通过单击组件的相应html元素触发routerLink时,我的CustomRouterStateSerializer
的序列化方法似乎被多次调用。
您将在StackBlitz上找到以下说明的最小示例应用程序。
我的实现
这是我的router.reducer.ts
文件,其中包含RouterStateUrl接口和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
的随机数属于旧项目视图的状态。
NgRx Store DevTools的输出似乎与预期的一样。但是我不明白何时何地触发了其他控制台输出的序列化方法。我在任何状态下都找不到第一和第三控制台输出的任何随机数。现在,我要问自己是不是犯了一个错误(正在实现某些东西),或者这仅仅是正常现象(但是为什么?)。也许有些人可以告诉我。
答案 0 :(得分:1)
我尝试了一些方法,但最终它有助于查看@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()
以避免派生状态:路由器是路由器状态的源,它可以在任何给定时间更改。
因此,当需要序列化状态时,它将不会存储在某个位置,而是每次都会重新计算。
这就是为什么该函数被多次调用的原因。但是,由于串行器功能应该是纯函数,所以这根本不是问题,而只是设计的一部分。
在任何状态下都找不到第一和第三控制台输出的任何随机数。
reducer只会将路由器状态放入navigation
,cancel
和error
上的存储中,而不会放入request
和{{1} }。
这意味着,您在商店中看到的唯一随机数是源自navigated
动作的随机数。
其他所有东西都只是在“途中”使用。
现在,我要问自己是不是犯了一个错误(正在实施某些东西),或者这仅仅是正常行为(但是为什么?)。
您的实现看起来不错,您可以放心:这是正常的和预期的行为! ?请注意,您的序列化函数应该是纯函数。
希望这会有所帮助!