React中直接基于当前state更新状态为何正确?求详解
Hey there, let's break down why your original code is totally valid, and when you actually need the prevState callback version.
First, let's recap the two ways to update state with setState:
- Object-based update:
this.setState({ count: this.state.count + 1 }) - Function-based update:
this.setState(prevState => ({ count: prevState.count + 1 }))
Why your original code is safe
In your example, the click handler is an arrow function that runs synchronously in a React synthetic event. Here's the critical detail: React batches state updates that happen within synthetic events, and by the time the next click event fires, the previous state update has already been applied.
That means every time the user clicks the button, this.state.count in the handler is the current, up-to-date value of the state. There's no risk of using a stale value here because each click is a separate event, and React ensures the state is fresh when the handler runs.
When you do need the prevState callback
The PR reviewer's note ("only use the callback version when you can't be sure of the captured state value") is spot-on. You need the function-based update in these scenarios:
- Multiple state updates in the same event:
If you callsetStatemultiple times in one handler, the object-based update will use the same initial state value for all calls. For example:
Using the// This only increments count by 1, not 2 <button onClick={() => { this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 }); }}>Click me</button>prevStatecallback fixes this, since each update uses the previous update's result:// This increments count by 2 <button onClick={() => { this.setState(prevState => ({ count: prevState.count + 1 })); this.setState(prevState => ({ count: prevState.count + 1 })); }}>Click me</button> - Asynchronous operations:
If you're updating state inside asetTimeout,Promise.then, or any async function,this.statemight be stale because React hasn't applied pending state updates yet. For example:
The// Risky: this.state.count might not be the latest value when the timeout runs setTimeout(() => { this.setState({ count: this.state.count + 1 }); }, 1000);prevStatecallback guarantees you're using the most recent state, regardless of when the update runs.
Wrap-up
Your original code is correct because it's a single, synchronous state update in a synthetic event handler—React ensures this.state is fresh when the handler executes. The prevState callback is only necessary when you can't guarantee the captured state is the latest version (like with multiple updates or async code).
内容的提问来源于stack exchange,提问作者Ярослав Терещук

