Using react useImmerReducer is causing a side effect that duplicates the changed item in a deeply nested array

128 Views Asked by At

I'm trying to update an object in a deeply nested array with useImmerReducer on React. For simplicity, the object looks like below

{ 
   flags: ['green', 'blue'],
   configs: [
      {
          baseTables: [
              {
                  name: 'Test',
                  action: 'run',
                  distance: 200
              }
           ]
      }
   ]
}

My reducer

const reducer = (draft, action) => {
    switch(action.type) {
       case 'EDIT':
          draft.configs[configIndex].baseTables[btIndex].name = 'NameChanged'
       break
    }
    ...more cases below
}

Then I have the useImmerReducer

const [state, dispatch] = useImmerReducer(reducer, defaultState)

Whenever I dispatch the EDIT action, it does find the correct item that needs to be changed. I can see that all arrays and items are proxied as expected by immer. However, when the action is complete, there's this side effect in which the old item gets updated correctly but a duplicate is created after React renders the page.

Other actions work perfectly fine (add, delete) where I push and splice items.

I have also tried doing the same without immer, with the below code:

const reducer = (draft, action) => {
switch(action.type) {
    case 'EDIT':
       return {
         ...draft,
         configs: [...draft.configs.map((config, index) => {
             if(index === configIndex) {
                 return {
                      ...config, 
                      baseTables: [...config.baseTables.map((bt, index) => {
                           if(index === btIndex) {
                                 return {
                                    ...bt,
                                    name: 'changedName'
                                  }
                            }
                            return bt
                       })
                      ]
                    }
              }
              return config
            })
        ]}
    }
}

What could be the problem? Thanks

1

There are 1 best solutions below

0
On

I ended up finding what the issue was.

I was using the same submitHandler to add/update with two if clauses to identify which action was being done. The problem was that I wasn't finalizing the update with a return statement, which cause the add function to run right after it.