1

我已经以常用的方式( 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属于旧项目视图的状态。

NgRx Store DevTools 的输出似乎符合预期。但是我不明白什么时候以及什么时候触发了其他控制台输出的序列化方法。在任何状态下,我都找不到第一个和第三个控制台输出的任何随机数。现在我问自己是我犯了错误(实现的东西)还是这只是正常的行为(但为什么?)。也许你们中的一些人可以告诉我。

4

1 回答 1

2

我尝试了一些东西,但最后有助于查看@ngrx/router-store. 这个模块本质上做的是监听所有路由器事件和调度动作。重要的一段代码是这个:https ://github.com/ngrx/platform/blob/master/modules/router-store/src/router_store_module.ts#L240-L275

But I don't understand when and what called the serialize method where the other console outputs were triggert.

You can see here that there are three situations where serialize() can be called:

  • at NavigationStart (directly)
  • at NavigationEnd (through the dispatchRouterNavigation() and dispatchRouterNavigated() methods)
  • at RoutesRecognized (through dispatchRouterNavigated())

Each of these events call serialize() separately to avoid derived state: The router is the source of the router state and it can change at any given time. Thus, when the serialized state is needed, it will not be stored somewhere but newly calculated each time instead. This is why the function is being called multiple times. However, since the serializer function should be pure, this is not a problem at all but rather part of the design.

I can not find any random numbers of the first and the third console output in any state.

The reducer will only put the router state into the store on navigation, cancel and error – but not on request and navigated. That means, the only random number you will see in the store is the one originating from the navigation action. All others are just used "on the way".

Now I'm asking myself if I have made an error (implementing stuff) or if this is just normal behaviour (but why?).

Your implementation looks good and you can be relieved: This is normal and intended behavior! Just be aware that your serializer function should be pure.

Hope this helps!

于 2019-08-15T16:03:50.877 回答