Reputation: 1176
How can I update multiple properties in my state object with and array of objects?
I have my state in this format:
{
1: { id: 1, values: [ 1, 2] },
2: { id: 2, values: [ 1, 2] }
}
In my reducer I receive the data to update the state in this format:
[
{ id: 1, values: [ 3, 4] },
{ id: 2, values: [ 3, 4 ] }
]
I want to be able to add the values from the objects coming into the reducer to matching object values in the state.
I would like to end up with:
{
1: { id: 1, values: [ 1, 2, 3, 4] },
2: { id: 2, values: [ 1, 2, 3, 4] }
}
I tried to map through this but then it was returning my state into an array. I want to keep my state as an object.
Upvotes: 1
Views: 2464
Reputation: 5016
Transform the data before it reaches your reducer, whether that's in an action, thunk, saga, or component.
const transform = (data = []) => {
const mappedData = {};
data.forEach(item => mappedData[item.id] = item);
return mappedData
}
// ...
data = transform(data)
This keeps reducer logic cleaner
const myReducer = (state = {}, { type, data = {}, id, values = [] }) => {
case 'SET_ALL':
return data;
case 'SET_MULTIPLE':
return {
...state,
...data
};
case 'SET':
return {
...state,
[id]: values
};
case 'APPEND_VALUES':
return {
...state,
[id]: {
...state[id],
values: [...state[id].values, ...values]
}
}
default:
return state;
}
Upvotes: 3
Reputation: 7209
The map solution was almost correct! I would recommend doing forEach
instead and don't return anything, but rather access a copy of state
by id
and modify those values (make sure you deep clone your state to avoid mutation). Then return the new state:
const myReducer = (state, action) => {
const newState = someDeepCloneFunction(state);
action.forEach(obj => {
newState[obj.id] = obj.values
})
return newState
}
Upvotes: 4