Search code examples
angulartypescriptngrxngrx-store

How can I set an entire NGRX store and then trigger all reducers?


How can I?

  1. Get entire NGRX store data
  2. Set entire NGRX store data
  3. Trigger all reducers

Background:

I have an angular application that has many components tightly coupled to an NGRX store.

I've reused these components for a flattened print layout of some of the information in the application. I use headless chrome to print the application to a pdf. Since the headless chrome is a different user-agent than the print-user's browser there is no data.

I initially solved this problem by posting over some of the NGRX store and having the headless chrome replace it in the store. However as the print view has expanded the amount of data needed from the store has grown to be unmanageable.

I would like to take the entire store data, then reinsert it into the other user-agent store, then trigger all reducers to ensure components update.

I already know how to get all of the store data. I could use some help on putting it back into the store. What I need most is how to trigger all reducers without writing hundreds of dispatch statements.


Solution

  • Something like this will do it:

    1. Get entire NGRX store:

      let storeData$ = store.select(rootReducers.getRootState);
      let subscription = storeData$.subscribe(everything => {
          let json = JSON.stringify(everything);
          //do what you want with all of your data here
      });
      
    2. Set entire NGRX store: (my top level reducer interface looks like this)

      export interface State { 
          something: topLevelReducers1.State;
          anything: topLevelReducers2.State;
          moreThings: topLevelReducers3.State;
      }
      

      This makes it necessary to set each of these top level fields:

      // here is the method //
      export const dispatchSetRootState = (store:Store<State>, payload: State): void => {
          store.dispatch(new SetSomethingState(payload.something));
          store.dispatch(new SetAnythingAction(payload.anything));
          store.dispatch(new SetMoreThingsAction(payload.moreThings));
      };
      
      // here is the usage //
      let everything = JSON.parse(json);
      dispatchSetRootState(store, data);
      
      // since I have a lot of combineReducers I add a short-circuit//
      export function reducers(state: any, action: any): any {
          if(action.type == SomethingActionTypes.SET_SOMETHING_PROFILE) { // Sets entire object
              return Object.assign({}, state, (<PayloadAction>action).payload);
          }
          else return combinedReducers(state, action);
      }
      
    3. Is not necessary because setting as in #2 triggers all actions