Taylor Ackley
Taylor Ackley

Reputation: 1437

Trouble Merging Object with State in Angular NgRx

I read this tutorial on creating a NgRx store so I created a simple store with the following shape.

export const initialState: IState = {
  app: initialAppState
};

export function getInitialState(): IState {
  return initialState;
}

export interface IApp {
  id?: string;
  testMode?: boolean;
  authenticated?: boolean;
  user?: User;
  role?: string;
}

export interface IAppState {
  app: IApp;
}

export const initialAppState: IAppState = {
  app: {
    id: null,
    testMode: false,
    authenticated: false,
    user: null,
    role: 'END_USER'
  }
};

It has one action PatchApp with a reducer that looks like this

export const appReducers = (state = initialAppState, action: AppActions): IAppState => {
  switch (action.type) {
    case AppActionTypes.PatchApp: {
      return { ...state, app: action.payload };
    }

    default:
      return state;
  }
};

Now to me, this seems super simple. We have an initial state that is stored in the app property. If we get a payload to update the authenticated property on the existing state, I would expect the reducer to overwrite just that property instead of the entire state.

But when I step through with the debugger, I can see the state get's updated with just the property that gets passed in.

So if I have the initial state like this:

export const initialAppState: IAppState = {
  app: {
    id: null,
    testMode: false,
    authenticated: false,
    user: null,
    role: 'END_USER'
  }
};

then I do PatchApp with {authenticated: true, id: 'someid'}, I would expect the action.payload to overwrite/merge/patch the existing object.

Instead what happens is the entire store get's overwritten with JUST the property. So after doing the afformentioned patch app, we would have just the authenticated and id props set.

Any idea why my reducer isn't behaving as expected? I read an article from Flavio Copes and don't see anything where I'm going wrong.

I also tried using Object.assign() to merge the objects.

return Object.assign({}, state, { app: action.payload });

I have a CodeSandbox that illustrates the problem I'm trying to solve.

https://codesandbox.io/s/oxj7xx5n35?fontsize=14

Upvotes: 0

Views: 871

Answers (1)

julianobrasil
julianobrasil

Reputation: 9377

Not sure whether I got right what you're trying to do, but it seems that you want to patch just the app part of the state. If so, you should do it like this:

export const appReducers = (state = initialAppState, action: AppActions): IAppState => {
  switch (action.type) {
    case AppActionTypes.PatchApp: {
      return { 
        ...state, 
        app: {...state.app, ...action.payload} 
      };
    }

    default:
      return state;
  }
};

Upvotes: 3

Related Questions