You're mixing the rest and spread syntax up. Both of them are an ellipse (...
), but are basically opposites of each other.
In your true case you're using spread, {...item, selected: true}
, to set all of the values in item
to the new object, and then adding the key selected
(potentially overriding a previous selected
key from item). Works fine.
In your else case you're using rest (and by extension, destructuring, {selected, ...item} = item
. Destructuring (and rest) are asignment only. Destructuring creates new variables or, if wrapped in parenthesis, reassigns old variables. Rest, in particular, means "take all of the entries I didn't ask for by name and shove them into a new object called [blank]". You are not adding a new object to an array. You are assigning the value of items.selected
to an undefined variable, selected
, and attempting to reassign the rest of the entries in item
to a new object ...also called item
. This won't work. Ever. If you're trying to remove item.selected
, then you could use destructuring like so:
...
} else {
let {selected, ...cleanedItem} = item;
item.selected && updating.push(cleanedItem);
!item.selected && updating.push(item);
}
...
You could also delete selected
from item
in your else case. delete
does mutate the original object, which is usually best avoided, but if you know it's safe (depends on the rest of your code), it's a valid option. Here's an example:
...
} else {
delete item.selected;
updating.push(item);
}
...
A third way to remove selected is to do the same thing you do in your true case, but setting
selectedto
undefined`:
...
} else {
updating.push({...item, selected: undefined});
}
...
Though, if you go that route you may as well get rid of the if
all together and use a ternary operator (expresion ? [true case] : [false case]
) instead. It can't do complex logic inside of the two cases, but you don't need to. That would look like this:
...
// replacing the if/else
updating.push({
...item,
selected: item.value == e.target.value
? true
: undefined
});
...
Or, if false is valid for selected
you can skip any conditional branching:
...
// replacing the if/else
updating.push({
...item,
selected: item.value == e.target.value
});
...
While we're at it, you may want to drop pushing to the updating
array all together. Map, unlike forEach
, is designed to return an array. Just return the value you want set for that item in the array:
const onChoiceChange = function setChoiceStateAndUpdateSelectedObject(e) {
let updating = choices.map((item, index) => {
return {
...item,
selected: item.value == e.target.value
}
});
setChoices(updating)
console.log('updating', updating)
}
Putting it all together (collapsed, because this answer is long as it is):
let choices = [
{ value: 1, text: 'This is value 1' },
{ value: 2, text: 'This is value 2' },
{ value: 3, text: 'This is value 3' },
{ value: 4, text: 'this is value 4' }
];
document.addEventListener('input', (e) => {
let updating = [];
if (e.target.getAttribute('name') == "choices") {
updating = choices.map(item => ({
...item,
selected: item.value == e.target.value
}));
}
console.log(updating)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<input type='radio' name='choices' value='1' />
<input type='radio' name='choices' value='2' />
<input type='radio' name='choices' value='3' />
<input type='radio' name='choices' value='4' />
As a parting note, the reason for the syntax error in the first place. It's mentioned above in the part about destructuring, but I figured I'd address it directly. When you destructure, you need to either use a declarative key word (let
, const, or
var`) to create a new variable, or use existing variables and parenthesis. You cannot mix and match, you need to either need to use all new variables or reuse all existing variables. Like so:
// new variables
// - can't be the same name as a defined variable in scope
let {selected, ...cleanedItem} = item;
// or with existing variables
// - the existing variables must be in scope
// - we'll assume item is in scope, same as your examples
let selected;
({selected, ...item} = item);
So the reason you get the syntax error is because you're trying to mix new and old variables together. selected
(as others have noted) isn't defined. Along with that (though no error would be thrown) if you try to return the result of a destructure, you actually return the unmodified original item you are destructuring from. So selected
wouldn't be removed at all, even if the destructuring syntax was used correctly. Fun, no?