React 事件处理与状态更新
说明 React 中事件处理与状态更新如何协作,强调不可变更新、批处理与事件里读 state 的边界。
#type / synthesis
#status / growing
#tech / dev / frame
#resource / react
[!info] 关联笔记
- 所属:React 基础 MOC
- 前置:useState · props/state/ref
- 后续:useEffect · 重渲染
React 事件处理与状态更新
这个概念为什么出现
点击“入库 +1”连点两次只加一次、事件里读到旧库存、把 DOM 当真相——都说明事件处理与状态更新的契约不清。
[!abstract] 一句话理解 事件处理器负责把用户意图变成 state 请求;UI 由下一次渲染的 state 推导,而不是在事件里直接改 DOM。
最小可运行示例
场景:扫码枪连扫导致库存快速累加
import { useState } from 'react'
export function InboundCounter() {
const [qty, setQty] = useState(0)
function handleScan() {
// 教学点:函数式更新避免连续事件读到过期闭包值
setQty((n) => n + 1)
}
function handleReset() {
setQty(0)
}
return (
<div>
<p>待上架数量:{qty}</p>
<button type="button" onClick={handleScan}>模拟扫码</button>
<button type="button" onClick={handleReset}>清零</button>
</div>
)
}
结合场景关注点
onClick传函数,不写onClick={handleScan()}。- 连续更新用
setQty(n => n+1)。 - 不要在事件里
document.querySelector改文本冒充状态。
核心模型
- 触发事件 → 调用处理器
- 处理器调度状态更新
- React 批处理/渲染
- 提交 DOM
合成事件提供跨浏览器事件对象接口;细节随版本演进,重点是声明式状态。
边界
- 事件中读到的 state 是当次渲染快照
- 需要读最新值又不触发渲染 → ref
- 异步事件后 setState 仍安全,但要处理卸载/竞态
常见误区
[!warning] 常见误区:直接 mutation 数组/对象再 set 同一引用 可能不触发重渲染;应创建新引用。
本节总结
事件是意图入口,state 是事实来源;函数式更新与不可变数据是正确性基础。
自测题
- 为什么
onClick={fn()}错误? - 连点三次
setCount(count+1)可能怎样?
参考答案
- 渲染时立即调用,传给 onClick 的是返回值。
- 可能基于同一旧 count 计算,只加 1;应用函数式更新。