簡體   English   中英

NgRx:多次調用 CustomRouterStateSerializer serialize()

[英]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()以避免派生狀態:路由器是路由器狀態的來源,它可以在任何給定時間更改。 因此,當需要序列化狀態時,它不會存儲在某處,而是每次都重新計算。 這就是該函數被多次調用的原因。 然而,由於串行器函數應該是純的,這根本不是問題,而是設計的一部分。

我在任何狀態下都找不到第一個和第三個控制台輸出的任何隨機數。

減速器只會在navigationcancelerror將路由器狀態放入存儲中——而不是在requestnavigated 這意味着,您將在商店中看到的唯一隨機數是源自navigation操作的隨機數。 所有其他人都只是在“途中”使用。

現在我問自己是否犯了錯誤(實施的東西),或者這是否只是正常行為(但為什么?)。

您的實現看起來不錯,您可以放心了:這是正常的和預期的行為! 🙂 請注意,您的序列化程序函數應該是純的。

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM