外观
setState 是同步的吗?
setState 安排一次更新,不保证在下一行就能读到新状态。React 18 在事件处理、Promise、定时器里都会把同一轮里的多次更新合并。要基于旧状态计算,传入函数。
原理
类组件的 setState(partial) 是浅合并。函数组件的 useState 替换整个状态,对象要自己展开。两者都支持函数形式,参数是这一次更新队列里的上一个状态。
jsx
setCount((count) => count + 1)同一事件里写两次 setCount(count + 1),如果 count 来自这次渲染的闭包,两次都是同一个数加一。函数形式才会累加。
更新被标上优先级。输入用紧急更新,大列表可以用 startTransition 标成可打断。见 React Fiber。
类组件的 setState 第二个参数是更新提交后的回调。函数组件里对应的是 useEffect,它在绘制之后。
追问
什么时候看起来像同步?
在 React 控制的事件里,处理函数跑完才会重新渲染,所以下一行读 this.state 仍是旧的。不要用「异步函数」来描述它。它是调度,不是返回 Promise 的 API。useState 的 setter 也不要 await。
对象状态会被深合并吗?
不会。类组件只合并第一层。嵌套字段要先拷贝再改。函数组件连第一层也不会替你合并。
易错点
- 连续非函数形式的更新互相覆盖。
- 在
render里调用setState。条件不严就会死循环。 - 把 props 复制进 state 后,父组件更新了,子组件的 state 还是旧的。能从 props 算出来的值不要再存一份。