标准答案

  1. 类组件 setState 和函数组件 useState 都支持函数式更新,用上一次状态作为参数计算下一次状态。
  2. 当多次更新依赖同一个旧值时,函数式更新可以避免闭包里的旧快照造成覆盖。
  3. 如果只是不依赖旧值的替换,例如 setOpen(true),直接传值即可。
  4. 如果需要马上使用新值,可以先在当前函数里计算 const next = count + 1,再 setCount(next) 并把 next 传给后续逻辑。
  5. 不要用强制同步或读取 DOM 的方式绕过 React 更新模型,除非确实是少数需要 flushSync 的集成场景。

题目解析

这道题和上一题相连,核心是区分“替换状态”和“基于旧状态推导新状态”。

函数式更新不会让当前闭包里的 count 立刻改变,它只是确保 React 处理更新队列时按正确顺序计算。

实际业务里常见场景包括计数器、分页、选中集合、展开折叠集合和表单数组更新。

代码示例

下面用函数式更新保证连续点击或连续调用时不会丢更新。

TSX
function TodoList() {
  const [selectedIds, setSelectedIds] = useState<string[]>([])

  function toggle(id: string) {
    setSelectedIds(prev => (
      prev.includes(id)
        ? prev.filter(item => item !== id)
        : [...prev, id]
    ))
  }

  return <button onClick={() => toggle('todo-1')}>切换选中</button>
}

常见误区

  • 只要连续 setState 就一律认为 React 会自动合并成想要的结果。
  • 数组或对象状态直接原地修改,再 set 回同一个引用。
  • 需要新值参与请求或校验时,没有先计算 nextValue,导致使用旧 state。

作者信息