标准答案
- 类组件 setState 和函数组件 useState 都支持函数式更新,用上一次状态作为参数计算下一次状态。
- 当多次更新依赖同一个旧值时,函数式更新可以避免闭包里的旧快照造成覆盖。
- 如果只是不依赖旧值的替换,例如 setOpen(true),直接传值即可。
- 如果需要马上使用新值,可以先在当前函数里计算 const next = count + 1,再 setCount(next) 并把 next 传给后续逻辑。
- 不要用强制同步或读取 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。