0
votes

In angular universal project in ssr mode after successfully importing transferred state into store, next dispatched action @ngrx/store/update-reducers wipes the store. Actually there are multiple @ngrx/store/update-reducers actions fired (>10).

Inspecting in @ngrx/store-devtools (chrome extension) shows incorrectly that store after @ngrx/store/update-reducers is still filled with data but it's not true, I see that previously loaded data in cmp disappears after a quick moment (when this mentioned action fires).

It only happens in ssr mode, although multiple @ngrx/store/update-reducers are still present in @ngrx/store-devtools in classic ng serve.

deps: angular 5.2.7, @ngrx/{store,effects,store-devtools,router-store} 5.2.0, chrome 66

1

1 Answers

1
votes

Usually @ngrx/store/update-reducers adds reducers from lazy loaded feature modules. Thus I assume that in your case multiple feature modules are lazy loaded.

What most probably happens is that transferred state is set before reducers for lazy loaded modules are added. By default ngrx will clear all parts of state that have no reducers assigned (this is done in combineReducers function which runs on every action dispatched).

Possible solutions:

1. Assign default reducers in root module for feature modules

StoreModule.forRoot(initialReducerMap, { initialState: getInitialState })
export function defaultReducer(state) { return state; }

export const initialReducerMap = {
    // this will make sure `feature1` and `feature2` parts are not cleared on next action
    feature1: defaultReducer,
    feature2: defaultReducer
} as ActionReducerMap<ApplicationState>;


export function getInitialState() {
    return {
        feature1: feature1.initialState,
        feature2: feature2.initialState
    };
}

More info in this blog post

2. Manually set transferred state parts for lazy loaded modules

import { ActionReducer, UPDATE } from "@ngrx/store";

let transferedState: any;
export function stateSetter(reducer: ActionReducer<any>): ActionReducer<any> {
  return function(state: any, action: any) {
    if (action.type === 'SET_ROOT_STATE') {
      transferedState = action.payload;
      return action.payload;
    }

    // on "update-reducers" set their initial transfered state
    if (action.type === UPDATE && transferedState && action.features) {
        const features: string[] = (action as any).features;
        const newState = { ...state };
        for (const feature of features) {
            newState[feature] = newState[feature] || transferedState[feature];
        }
        return reducer(newState, action);
    }

    return reducer(state, action);
  };
}

Other

Refer to this github issue