React 事件处理与状态更新

说明 React 中事件处理与状态更新如何协作,强调不可变更新、批处理与事件里读 state 的边界。

#type / synthesis #status / growing #tech / dev / frame #resource / react

[!info] 关联笔记

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>
  )
}

结合场景关注点

  1. onClick 传函数,不写 onClick={handleScan()}
  2. 连续更新用 setQty(n => n+1)
  3. 不要在事件里 document.querySelector 改文本冒充状态。

核心模型

  1. 触发事件 → 调用处理器
  2. 处理器调度状态更新
  3. React 批处理/渲染
  4. 提交 DOM

合成事件提供跨浏览器事件对象接口;细节随版本演进,重点是声明式状态

边界

  • 事件中读到的 state 是当次渲染快照
  • 需要读最新值又不触发渲染 → ref
  • 异步事件后 setState 仍安全,但要处理卸载/竞态

常见误区

[!warning] 常见误区:直接 mutation 数组/对象再 set 同一引用 可能不触发重渲染;应创建新引用。

本节总结

事件是意图入口,state 是事实来源;函数式更新与不可变数据是正确性基础。

自测题

  1. 为什么 onClick={fn()} 错误?
  2. 连点三次 setCount(count+1) 可能怎样?
参考答案
  1. 渲染时立即调用,传给 onClick 的是返回值。
  2. 可能基于同一旧 count 计算,只加 1;应用函数式更新。
创建于 2026/3/19 更新于 2026/7/15