I’m trying to compare the current state of selected options against an incoming state of options. The incoming state will have property selected
which is a boolean.
What I’m trying to accomplish is this: If an item in the incomingOptions
has selected: true
, update the same item in currentState
or add it to the current state if it doesn’t exist. If selected: false
, the item should not be returned in the new state.
const currentState = {
products: [
{
optionid: 808541,
quantity: 7
},
{
optionid: 808542,
quantity: 7
},
{
optionid: 808543,
quantity: 6
},
{
optionid: 808546,
quantity: 7
},
{
optionid: 808547,
quantity: 7
},
{
optionid: 808548,
quantity: 7
},
{
optionid: 808549,
quantity: 1
},
{
optionid: 808550,
quantity: 7
},
{
optionid: 808551,
quantity: 7
},
{
optionid: 808552,
quantity: 7
},
{
optionid: 808553,
quantity: 7
}
]
};
const incomingOptions = [
{
id: 808539, // this item is new
selected: true,
quantity: 5
},
{
id: 808540, // this item is new
selected: true,
quantity: 5
},
{
id: 808541, // this item exists in current state, but is now false
selected: false,
quantity: 5
},
{
id: 808542, // this item exists in current state, but the quantity is now 10
selected: true,
quantity: 10
},
{
id: 808543,
selected: false
},
{
id: 808544,
selected: false
},
{
id: 808545,
selected: false
}
];
The final state I’m after is this:
products: [
{
"optionid": 808542,
"quantity": 10
},
{
"optionid": 808546,
"quantity": 7
},
{
"optionid": 808547,
"quantity": 7
},
{
"optionid": 808548,
"quantity": 7
},
{
"optionid": 808549,
"quantity": 1
},
{
"optionid": 808550,
"quantity": 7
},
{
"optionid": 808551,
"quantity": 7
},
{
"optionid": 808552,
"quantity": 7
},
{
"optionid": 808553,
"quantity": 7
},
{
"optionid": 808539,
"quantity": 5
},
{
"optionid": 808540,
"quantity": 5
}
]
I’ve tried using reduce
with a combination of findIndex
, but I’m finding that I’m needing to loop things over several times and it feels really inefficient.
Forgot my first pass, which updates the current items, but not any new items:
const updatedState = state.products.reduce((acc, curr) => {
const option = currentOptions.find((opt) => opt.id === curr.optionid);
if (option) {
return option.selected
?
[
...acc,
{
...curr,
quantity: option.quantity
}
]
: acc;
}
return [...acc, curr];
}, []);
2
Answers
If you’re able to slightly modify the input data:
— it can be simplified to:
Given the above you can just use a simple, readable, easily debuggable
forEach
like:Readable, reasonable, and developer friendly.
If you really want to stick to something more compact (no reason to), you can always do:
It works for me: