Can someone explain why this code works?
import { useState } from 'react';
export default function RandomList() {
const [numbers, setNumbers] = useState([]);
const addNumber = () => {
setNumbers(whatever => {
return [...whatever, Math.random()];
});
};
return (
<div>
<h1>Random Numbers</h1>
<button onClick={addNumber}>Add a Number</button>
<ul>
{numbers.map((number, index) => (
<li key={index}>{number}</li>
))}
</ul>
</div>
);
}
Namely:
(1) Where is whatever being stored, is it in a closure inside the function? Or is it merely a temporary parameter which is used to update the internal state of numbers?
(2) Is there any advantage in sending a function into the useState setter as in the above code, rather than doing this:
numbers.push(Math.random());
setNumbers([...numbers]);
Where is whatever being stored,
whatever is the argument to the function you've created. React will call your function, passing in the current value of the state as that argument, and then you return what you want the new state to be.
Is there any advantage in sending a function into the useState setter as in the above code, rather than doing this:
The function version of set state guarantees that you're using the latest value of the state, and so it makes a category of bugs related to stale closure variables impossible.
For example, if you try to set state twice in a row without using the function, the second set state will overwrite the first and so you only get one new number:
setNumbers([...numbers, Math.random()]);
setNumbers([...numbers, Math.random()]);
But if you use the function version instead, it will keep both changes:
setNumbers(prev => [...prev, Math.random()]);
setNumbers(prev => [...prev, Math.random()]);
Of course, you probably won't write two lines of code like that right next to eachother, but in complicated components you can get similar behavior, just with the lines of code not so obviously related.
Is there any advantage in sending a function into the useState setter as in the above code, rather than doing this:
When setNumbers([...numbers]); updates the state, the changes are not reflected immediately in the count variable. Rather React schedules a state update, and during the next rendering in the statement const [numbers, setNumbers] = useState([]); the hook assigns to numbers the new state value.
so to avoid this asynchronous nature and we pass callback to setNumber();