2

Can anyone help with this update pattern. I am not using any libraries like immer.

I have to update a nested object and the data looks like dis

Sample data

    { 
      isFetching: false
      data:{
            nba : {
                    stack :{
                            1:[]
                           }
                  }
           }
    }

My Reducer

 {
        ...state,
        isFetching: false,
        data: {
          ...state.data,
          [action.payload.team]: {
            ...state[action.payload.team],
            [action.payload.framework]: {
              ...state[action.payload.framework],
              [action.payload.build]: action.payload.resp
            }
          }
        }
 };

I am able to update until second level but unable to update third child. can anyone throw a light on where i am missing it.

I put a demo on codesandbox. https://codesandbox.io/s/todos-0ygrs

Click on collapse and inner collapse items. I am logging the changes for the state in the console below. As you can see at last level, build numbers are getting replaced with the new one's.

Current Behaviour After you expand nba and all the three childs

  {
    nba: {
           stack:{
                  3:[]
          }
  }

Expected Behaviour: After you expand stack and all the three childs

 {
    nba: {
           stack:{
                   1:[],
                   2:[],
                   3:[]
               }
         }
   }
Hemanthvrm
  • 2,319
  • 1
  • 17
  • 26
  • @joseph.. nope, have you expanded all the children panels?..I dont see expected behaviour as mentioned above..it is just showing only 1 panel id which we expand at last Ex: stack{ 1: [ ] } and it is updating to stack: { 2: [ ]} if we expand second panel.. where as i am looking for stack:{ 1:[ ], 2:[ ]} – Hemanthvrm Oct 11 '19 at 03:51

2 Answers2

1

You probably have to use a get helper because you may try to set a part of state that doesn't exist yet.

With the get helper you can set the state like this:

const { team, framework, build, resp } = action.payload;
const newState = {
  ...state,
  isFetching: false,
  data: {
    ...get(state, ['data']),
    [team]: {
      ...get(state, ['data', team]),
      [framework]: {
        ...get(state, ['data', team, framework]),
        [build]: resp,
      },
    },
  },
};
HMR
  • 37,593
  • 24
  • 91
  • 160
1

Somehow i figured out my mistake, Hope it helps someone in future

Initial state should not be null, it should be empty object and update pattern should be in this manner

 {
    ...state,
    isFetching: false,
    data: {
      ...state.data,
      [action.payload.team]: {
        ...state.data[action.payload.team],
        [action.payload.framework]: {
          ...state.data[action.payload.team][action.payload.framework],
          [action.payload.build]: action.payload.resp
        }
      }
    }
  };

if it fails, then try this way

let teamTemp = { ...state.data[action.payload.team]}

     {
        ...state,
        isFetching: false,
        data: {
          ...state.data,
          [action.payload.team]: {
            ...teamTemp ,
            [action.payload.framework]: {
              ...teamTemp[action.payload.framework],
              [action.payload.build]: action.payload.resp
            }
          }
        }
      };

I have forked my codesandbox and updated latest code.

Hemanthvrm
  • 2,319
  • 1
  • 17
  • 26