I would like to concatenate one item in the array with another one and remove the second item from the array. When I tried the old way, I get the state mutation detected error. When I tried the Object.assign
, I am unable to get the values concatenated.
EDIT:
What is the equivalent of interests[makeIndex].value = ``${interests[makeIndex].value}, ${interests[secondPreferredMakeIndex].value}``
using Object.assign
?
For e.g., for the below code segment the output I expect is,
Preferred Make - before Chevrolet
Preferred Make - after Chevrolet, Porsche
// Interests array from state
let interests = [
{
type: 'Preferred Make',
value: 'Chevrolet',
},
{
type: 'Second Preferred Make',
value: 'Porsche',
},
{
type: 'Preferred Model',
value: 'Corvette',
},
{
type: 'Second Preferred Model',
value: 'Macan',
}
];
console.log("Preferred Make - before", interests[0].value);
const secondPreferredMakeIndex = interests
.map(x => x.type)
.indexOf('Second Preferred Make');
if (secondPreferredMakeIndex > -1) {
let makeIndex = interests.map(x => x.type).indexOf('Preferred Make');
if (makeIndex > -1) {
// For the below, I get mutation error. But it works
// interests[makeIndex].value = `${interests[makeIndex].value}, ${interests[secondPreferredMakeIndex].value}`;
// Concatenate and use Object.assign to avoid mutation
interests = Object.assign([], interests, { makeIndex: `${interests[makeIndex].value}, ${interests[secondPreferredMakeIndex].value}` });
/*
// Tried the below as well in vain
interests = Object.assign([], interests, {
makeIndex: {
type: 'Preferred Make',
value: `${interests[makeIndex].value}, ${interests[secondPreferredMakeIndex].value}`
},
});
*/
}
// Delete the second Preferred Make
interests.splice(secondPreferredMakeIndex, 1);
}
console.log("Preferred Make - after", interests[0].value);
Appreciate the helps
Anything you select from the Redux store is still a reference to that object in the store. The UI should not mutate these references!
interests[makeIndex].value = `${interests[makeIndex].value}, ${interests[secondPreferredMakeIndex].value}`;
mutates the interests[makeIndex].value
state value.
The interests = Object.assign([], interests, { makeIndex: `${interests[makeIndex].value}, ${interests[secondPreferredMakeIndex].value}` });
is also a mutation since it re-assigns the entire interests
array value.
The code also creates a new makeIndex
property on the object instead of updating the value
property.
You should create a "deep copy" (copy the array and array elements into new object references) of the selected interests
state since you want to update specific elements and remove elements from the array. For demonstration purposes I'm simply using JSON.parse(JSON.stringify(interests))
to "clone" the object.
Use the value
key instead of makeIndex
for the element object you want to update.
Object.assign(
interestsCopy[makeIndex],
{
value: `${interestsCopy[makeIndex].value}, ${interestsCopy[secondPreferredMakeIndex].value}`
}
);
// Interests array from state
let interests = [
{
type: 'Preferred Make',
value: 'Chevrolet',
},
{
type: 'Second Preferred Make',
value: 'Porsche',
},
{
type: 'Preferred Model',
value: 'Corvette',
},
{
type: 'Second Preferred Model',
value: 'Macan',
}
];
// "deep copy"
let interestsCopy = JSON.parse(JSON.stringify(interests));
console.log("Preferred Make - before (orig)", interests[0].value);
console.log("Preferred Make - before (copy)", interestsCopy[0].value);
const secondPreferredMakeIndex = interestsCopy
.map(x => x.type)
.indexOf('Second Preferred Make');
if (secondPreferredMakeIndex > -1) {
let makeIndex = interestsCopy.map(x => x.type).indexOf('Preferred Make');
if (makeIndex > -1) {
Object.assign(
interestsCopy[makeIndex],
{
value: [
interestsCopy[makeIndex].value,
interestsCopy[secondPreferredMakeIndex].value
].join(", "),
}
);
}
// Delete the second Preferred Make
interestsCopy.splice(secondPreferredMakeIndex, 1);
}
console.log("Preferred Make - after (orig)", interests[0].value);
console.log("Preferred Make - after (copy)", interestsCopy[0].value);
A more correct solution may be to map the current interests
array to a new array with a new element object that you want to update, then filter the old element out of the array.
Example:
// Interests array from state
let interests = [
{
type: 'Preferred Make',
value: 'Chevrolet',
},
{
type: 'Second Preferred Make',
value: 'Porsche',
},
{
type: 'Preferred Model',
value: 'Corvette',
},
{
type: 'Second Preferred Model',
value: 'Macan',
}
];
const interestsCopy = interests.map((el, index, arr) => {
const { type, value } = el;
switch(type) {
case "Preferred Make":
return {
type,
value: [
value,
arr.find(el => el.type === "Second Preferred Make")?.value
]
.filter(Boolean)
.join(", "),
};
default:
return el;
}
}).filter(({ type }) => type !== "Second Preferred Make");
console.log("Preferred Make - after (orig)", interests[0].value);
console.log("Preferred Make - after (copy)", interestsCopy[0].value);