Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transferred (initial) state is cleared for lazy loaded modules #1846

Closed
pawelgur opened this issue May 9, 2019 · 1 comment
Closed

Transferred (initial) state is cleared for lazy loaded modules #1846

pawelgur opened this issue May 9, 2019 · 1 comment

Comments

@pawelgur
Copy link

pawelgur commented May 9, 2019

I'm submitting a...


[ ] Regression
[X] Bug report 
[X] Feature request
[ ] Documentation issue or request

Prerequisites

Server side rendering set up with state transfer as per #101 - server state is set on client with custom action (triggered by effect) on app init by meta reducer:

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

App includes lazy loaded modules which are loaded on server side and their state is also transferred to client.

Flow (client):

  1. app init
  2. set transferred state
  3. [some other actions]
  4. route activate action which lazy loads feature modules

What is the current behavior?

Any action (step 3) clears transferred state parts for not yet loaded modules. Transferred state is not available for lazy loaded modules (step 4).

Expected behavior:

Transferred state for lazy loaded modules is not cleared and is available upon loading.

Cause

Before lazy loaded module is loaded, its reducers are not yet registered.
combineReducers runs for any action and clears any state parts that have no reducers registered, related code here

Other information:

"@angular/core": "^7.2.9",
"@ngrx/store": "^7.3.0",

Same issue mentioned in #324 (although refers to initial state, not transferred), similar in #906.

Possible solutions

1. Update combineReducers

Update util to preserve state even for missing reducers, change this line to: const nextState: any = {...state};

2. Provide default reducers for feature modules in root module

Details in this comment.

3. 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);
  };
}

4. Use custom reducer factory

Custom combineReducers could be implemented preserving initial state

StoreModule.forRoot(APP_REDUCER_TOKEN, {
        // same `combineReducers` with change from solution 1
	reducerFactory: combineReducersCustom  
}),

What would you suggest?

IMHO ideally this would be solved from ngrx side once, not requiring all consumers to implement one of these solutions (each having its own drawbacks).

@pawelgur pawelgur changed the title Transfered (initial) state is cleared for lazy loaded modules Transferred (initial) state is cleared for lazy loaded modules May 9, 2019
@brandonroberts
Copy link
Member

Plesse test with the latest release and reopen if this is still an issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants