I followed the answer in this thread to try to update my deeply nested object in React. React: Setting State for Deeply Nested Objects w/ Hooks
What seems to work like a charm there, will somehow break for me when doing the following:
I have a table populated with items from an array defined like so:
const [items, setItems] = useState([
{
selected: false,
title: 'Item 1',
status: 'new'
},
{
selected: false,
title: 'Item 2',
status: 'used'
},
]);
When selecting an item from that list this function gets called to update selected
variable for the object with the index i
like so:
const select = (e) => {
const i = e.target.getAttribute('data-index');
setItems((prevState) => {
prevState[i].selected = !prevState[i].selected;
return [...prevState];
});
};
This will work exactly once. If I trigger select
a second time or any time after that return [...prevState]
somehow keeps returning the state unchanged. (selected
stays true
forever). I can't solve this.
items
is attached to a ponent List
like so:
<List
items={items}
/>
and inside List
(shortened code):
{items.map((item, i) => {
return (
<tr className="list-table-tr">
{hasSelector ? (
<td className="list-table-td-selector">
{item.selected ? (
<div
data-index={i}
className="global-selector-selected"
onClick={select}
></div>
) : (
<div
data-index={i}
className="global-selector-unselected"
onClick={select}
></div>
)}
</td>
) : null}
I followed the answer in this thread to try to update my deeply nested object in React. React: Setting State for Deeply Nested Objects w/ Hooks
What seems to work like a charm there, will somehow break for me when doing the following:
I have a table populated with items from an array defined like so:
const [items, setItems] = useState([
{
selected: false,
title: 'Item 1',
status: 'new'
},
{
selected: false,
title: 'Item 2',
status: 'used'
},
]);
When selecting an item from that list this function gets called to update selected
variable for the object with the index i
like so:
const select = (e) => {
const i = e.target.getAttribute('data-index');
setItems((prevState) => {
prevState[i].selected = !prevState[i].selected;
return [...prevState];
});
};
This will work exactly once. If I trigger select
a second time or any time after that return [...prevState]
somehow keeps returning the state unchanged. (selected
stays true
forever). I can't solve this.
items
is attached to a ponent List
like so:
<List
items={items}
/>
and inside List
(shortened code):
{items.map((item, i) => {
return (
<tr className="list-table-tr">
{hasSelector ? (
<td className="list-table-td-selector">
{item.selected ? (
<div
data-index={i}
className="global-selector-selected"
onClick={select}
></div>
) : (
<div
data-index={i}
className="global-selector-unselected"
onClick={select}
></div>
)}
</td>
) : null}
Share
Improve this question
edited Sep 21, 2021 at 14:52
smac89
43.3k15 gold badges150 silver badges198 bronze badges
asked Sep 21, 2021 at 14:39
DawesignDawesign
7732 gold badges7 silver badges28 bronze badges
1
- There has to be a good dupetarget for this. Anyone have one? – T.J. Crowder Commented Sep 21, 2021 at 14:46
1 Answer
Reset to default 9You're breaking one of the primary rules of React state: You're modifying a state object directly, rather than making a copy.
To correctly do the update, you'd do this:
const select = (e) => {
const i = e.target.getAttribute('data-index');
setItems((prevState) => {
// Copy the array (your code was doing that)
const update = [...prevState];
const item = update[i];
// Copy the object (your code wasn't doing that) and update its
// `selected` property
update[i] = {...item, selected: !item.selected};
return update;
});
};
Note how both the array and the object are copied, rather than just the array.