i have a simple cart logic with use state i want to update object inside of array whos name is surya and because react strick mode print 2 times the first value was right but the second value make change to arr[0]
is there something i miss
const [coba, setCoba] = useState([
{ name: "aditya" },
{ name: "joni" },
{ name: "surya", money: 2000 },
]);
coba.forEach((item) => {
let arr = [];
if (item.nama === "surya") {
item.money = 500000;
arr.push(item);
setCoba((prev) => {
return [
{
...prev,
...arr,
},
];
});
}
});
console.log(coba);
it console like this
[
{ name: 'aditya' },
{ name: 'joni' },
{ name: 'surya', money: 500000 }
]
[
{
'0': { name: 'surya', money: 500000 },
'1': { name: 'joni' },
'2': { name: 'surya', money: 500000 }
}
]
i want to know why the second time it run its change the value of arr[0]object whos name: aditya
>Solution :
The behavior you observe is du to several mistakes:
Array manipulation:
- You have a prev array with three items: [0, 1, 2]
- You create a new array with only one item [0]
- You merge them inside an object, so the index from the arrays are gettings used as keys, since the new array comes second, its element at index 0 will erase the element at index 0 in prev. This is why surya is logged as the first item in the resulting array.
State manipulation:
You are modifying an element of the array in the state. Since object are manipulating by reference, you are updating the object at all places. This is why the third row gets modified too.
In addition you should never call ‘useState’ inside the rendering pat of a component or inside a loop (as pointed out in comments) or you might end with infinite rendering loops.
Here is a sample code pen doing what you want with a click handler (you can use useEfect if you prefer this to be done initially): https://codepen.io/aSH-uncover/pen/WNLOOdK
// Hooks //
const [coba, setCoba] = useState([
{ name: "aditya" },
{ name: "joni" },
{ name: "surya", money: 2000 },
]);
// Event Handlers //
const handleClick = () => {
setCoba((prev) => {
const surya = prev.find(c => c.name === 'surya')
surya.money += 1000
return [...prev];
});
}
// Rendering //
return (
<div>
{coba.map(c => <div>{c.name} {c.money}</div>)}
<button onClick={handleClick}>Give Money to Surya</button>
</div>
)