From ef1ba5fd885d5351b57fe41f4d005c97aba5097a Mon Sep 17 00:00:00 2001 From: dummdidumm <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 30 Jul 2018 16:37:28 +0200 Subject: [PATCH] #955 Make import action timing smarter: wait for first router navigation if there is one --- modules/store-devtools/src/extension.ts | 61 ++++++++++++++++--------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/modules/store-devtools/src/extension.ts b/modules/store-devtools/src/extension.ts index da2676458e..ac4e11efd0 100644 --- a/modules/store-devtools/src/extension.ts +++ b/modules/store-devtools/src/extension.ts @@ -1,7 +1,15 @@ -import { Inject, Injectable, InjectionToken } from '@angular/core'; +import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; import { Action } from '@ngrx/store'; import { empty, timer, of, Observable } from 'rxjs'; -import { filter, map, share, switchMap, takeUntil, concatMap } from 'rxjs/operators'; +import { + filter, + map, + share, + switchMap, + takeUntil, + concatMap, + take, +} from 'rxjs/operators'; import { PERFORM_ACTION, IMPORT_STATE } from './actions'; import { @@ -17,6 +25,7 @@ import { sanitizeStates, unliftState, } from './utils'; +import { NavigationEnd, Router } from '@angular/router'; export const ExtensionActionTypes = { START: 'START', @@ -27,7 +36,7 @@ export const ExtensionActionTypes = { export const REDUX_DEVTOOLS_EXTENSION = new InjectionToken< ReduxDevtoolsExtension - >('Redux Devtools Extension'); +>('Redux Devtools Extension'); export interface ReduxDevtoolsExtensionConnection { subscribe(listener: (change: any) => void): void; @@ -61,7 +70,8 @@ export class DevtoolsExtension { constructor( @Inject(REDUX_DEVTOOLS_EXTENSION) devtoolsExtension: ReduxDevtoolsExtension, - @Inject(STORE_DEVTOOLS_CONFIG) private config: StoreDevtoolsConfig + @Inject(STORE_DEVTOOLS_CONFIG) private config: StoreDevtoolsConfig, + @Optional() private router: Router ) { this.devtoolsExtension = devtoolsExtension; this.createActionStreams(); @@ -93,17 +103,17 @@ export class DevtoolsExtension { const currentState = unliftState(state); const sanitizedState = this.config.stateSanitizer ? sanitizeState( - this.config.stateSanitizer, - currentState, - state.currentStateIndex - ) + this.config.stateSanitizer, + currentState, + state.currentStateIndex + ) : currentState; const sanitizedAction = this.config.actionSanitizer ? sanitizeAction( - this.config.actionSanitizer, - action, - state.nextActionId - ) + this.config.actionSanitizer, + action, + state.nextActionId + ) : action; this.extensionConnection.send(sanitizedAction, sanitizedState); } else { @@ -162,15 +172,24 @@ export class DevtoolsExtension { map(change => this.unwrapAction(change.payload)), concatMap((action: any) => { if (action.type === IMPORT_STATE) { - // State imports may happen in two situations: - // 1. Explicitly by user - // 2. User activated the "persist state accross reloads" option - // and now the state is imported during reload. - // Because of option 2, we wait for 1 second before continueing to give possible - // lazy loaded reducers time to instantiate. - // Unfortunately, there is no way to know which lazy loaded reducers - // are not loaded yet and if they are needed, so we just wait a little. - return timer(1000).pipe(map((t: number) => action)); + if (this.router) { + if (!this.router.navigated) { + // If router exists and import happens straight at app start, + // wait until the first navigation happened to make sure every + // possibly lazy loaded reducer exists + return this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + take(1), + map(() => action) + ); + } else { + return of(action); + } + } else { + // If no router exists, conservatively wait 1 second, maybe user uses + // a different router implementation + return timer(1000).pipe(map((t: number) => action)); + } } else { return of(action); }