andrux
andrux

Reputation: 2922

Merge state with array of objects ignoring duplicates in React Native Redux

I have an initial state like this:

export const INITIAL_STATE = Immutable({
  payload: []
})

When I dispatch the request action, it returns an array of objects, something like this:

[
  {id: 1, name: 'userA'},
  {id: 2, name: 'userB'},
  {id: 3, name: 'userC'}
]

So, when I try to refresh the state, I merge the existing payload with the new one I get from my server:

export const success = (state, { payload }) => {
  const newPayload = state.payload.concat(payload)

  return state.merge({ payload: newPayload })
}

This makes my new state end up something like this:

[
  {id: 1, name: 'userA'},
  {id: 2, name: 'userB'},
  {id: 3, name: 'userC'},
  {id: 4, name: 'userD'},
  {id: 5, name: 'userE'},
  {id: 6, name: 'userF'}
]

So, that part works, but, if I call again my request action, the state is getting populated with duplicated data, like this:

[
  {id: 1, name: 'userA'},
  {id: 2, name: 'userB'},
  {id: 3, name: 'userC'},
  {id: 4, name: 'userD'},
  {id: 5, name: 'userE'},
  {id: 6, name: 'userF'},
  {id: 1, name: 'userA'}, // <== duplicated data
  {id: 2, name: 'userB'}, // <== duplicated data
  {id: 3, name: 'userC'}  // <== duplicated data
]

What I need is that if I call the request action, and the same data is returned from the server - in this case ids 1, 2 and 3 - then for state.merge to just leave the payload as it is or update them with new values if that's the case, so if user with id 2 updated his name in the server to newUserB then my new state would be like:

[
  {id: 1, name: 'userA'},
  {id: 2, name: 'newUserB'},
  {id: 3, name: 'userC'},
  {id: 4, name: 'userD'},
  {id: 5, name: 'userE'},
  {id: 6, name: 'userF'}
]

instead of this:

[
  {id: 1, name: 'userA'},
  {id: 2, name: 'userB'},
  {id: 3, name: 'userC'},
  {id: 4, name: 'userD'},
  {id: 5, name: 'userE'},
  {id: 6, name: 'userF'},
  {id: 1, name: 'userA'},
  {id: 2, name: 'newUserB'},
  {id: 3, name: 'userC'}
]

I have tried using state.merge({ payload: newPayload }, {deep: true}) but it's not working the way I expect, I also tried state.merge({ payload }) and the same.

Anyone knows how to accomplish this?

Upvotes: 4

Views: 4559

Answers (1)

therewillbecode
therewillbecode

Reputation: 7180

Firstly merge the two arrays and then filter only unique items.

export const success = (state, { payload }) => {       
   const newArr = state.payload.concat(payload)  
   const idPositions = newArr.map(el => el.id)
   const newPayload = newArr.filter((item, pos, arr) => {
                                return idPositions.indexOf(item.id) == pos;
                              })

   return state.merge({ payload: newPayload })
}

Upvotes: 2

Related Questions