Use option 1 when the new state is independent of the previous state, like fetching data from a server and you are simply replacing current state.
Use option 2 when the next state depends on the current state, like incrementing a count.
BTW, option 2's pattern is called a functional update since you pass it a pure function that takes the current state, mutates it, and returns the next state.
The following is a counting demo I've created to really show the difference between the two and why the distinction is important.
const [count, setCount] = useState(0);
/**
* count +3 click handler using naive state updates.
*/
const clickHandler1 = () => {
// assume count equals some number n
setCount(count + 1); // update queued, count === n, count = n + 1
setCount(count + 1); // update queued, count === n, count = n + 1
setCount(count + 1); // update queued, count === n, count = n + 1
// when processed the count will be n + 1
};
/**
* count +3 click handler using functional state updates.
*/
const clickHandler2 = () => {
// assume count equals some number n
setCount(count => count + 1); // update queued, count === n + 0, count = prevCount + 1
setCount(count => count + 1); // update queued, count === n + 1, count = prevCount + 1
setCount(count => count + 1); // update queued, count === n + 2, count = prevCount + 1
// now when processed each call uses the result of the previous update
// count will be n + 1 + 1 + 1, or n + 3
};
