Skip to content

Commit

Permalink
#955 Make import action timing smarter: wait for first router navigat…
Browse files Browse the repository at this point in the history
…ion if there is one
  • Loading branch information
dummdidumm committed Jul 30, 2018
1 parent 1c0bdb8 commit 9e9c4f5
Showing 1 changed file with 40 additions and 21 deletions.
61 changes: 40 additions & 21 deletions modules/store-devtools/src/extension.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -17,6 +25,7 @@ import {
sanitizeStates,
unliftState,
} from './utils';
import { NavigationEnd, Router } from '@angular/router';

export const ExtensionActionTypes = {
START: 'START',
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 9e9c4f5

Please sign in to comment.