关于 rerender-functional-setstate
面向 React 开发者的编码技能,建议在状态更新依赖当前值时使用函数式 `setState`。它说明这种写法如何避免过期闭包,并减少依赖、保持回调稳定。
主要功能
- 01基于最新状态值更新
- 02避免过期闭包问题
- 03保持回调稳定
- 04减少 Hook 依赖项
适用场景
- 01向 state 数组追加项目
- 02在回调中更新状态
- 03在事件处理程序或异步操作中修改状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ theorcdev/ 8bitcn-ui --skill rerender-functional-setstate安装后在 Claude Code 中输入/rerender-functional-setstate确认已加载。
详细介绍
使用函数式 setState 更新
根据当前状态值更新状态时,请使用 setState 的函数式更新形式,而不是直接引用状态变量。这样可以避免闭包过期、消除不必要的依赖,并创建稳定的回调引用。
错误(需要将状态作为依赖项):
function TodoList() {
const [items, setItems] = useState(initialItems)
// Callback must depend on items, recreated on every items change
const addItems = useCallback((newItems: Item[]) => {
setItems([...items, ...newItems])
}, [items]) // items dependency causes recreations
// Risk of stale closure if dependency is forgotten
const removeItem = useCallback((id: string) => {
setItems(items.filter(item => item.id !== id))
}, []) // Missing items dependency - will use stale items!
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
}
第一个回调会在 items 每次变化时重新创建,这可能导致子组件不必要地重新渲染。第二个回调存在闭包过期问题——它始终会引用初始的 items 值。
正确(回调稳定,不会出现闭包过期):
function TodoList() {
const [items, setItems] = useState(initialItems)
// Stable callback, never recreated
const addItems = useCallback((newItems: Item[]) => {
setItems(curr => [...curr, ...newItems])
}, []) // No dependencies needed
// Always uses latest state, no stale closure risk
const removeItem = useCallback((id: string) => {
setItems(curr => curr.filter(item => item.id !== id))
}, []) // Safe and stable
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
}
优点:
- 回调引用稳定 - 状态变化时无需重新创建回调
- 不会出现闭包过期 - 始终基于最新的状态值进行操作
- 依赖项更少 - 简化依赖数组并减少内存泄漏
- 防止错误 - 消除最常见的 React 闭包错误来源
适合使用函数式更新的情况:
- 任何依赖当前状态值的 setState
- 在需要使用状态的 useCallback/useMemo 中
- 引用了状态的事件处理程序
- 更新状态的异步操作
适合直接更新的情况:
- 将状态设为静态值:
setCount(0) - 仅根据 props/参数设置状态:
setName(newName) - 状态不依赖之前的值
**注意:**如果你的项目启用了 React Compiler,编译器可以自动优化某些情况,但仍建议使用函数式更新,以确保正确性并防止闭包过期错误。
评论
支持 Markdown