React useState重置对象所有字段时仅最后一个字段生效问题
问题原因
当前reset方法的实现不符合React状态批量更新的规则:
- 循环调用
setValue时,每次展开的value都是当前渲染闭包中捕获的初始状态值,不是上一次setValue执行后的最新状态 - React会批量合并同一次事件中的多次state更新,最后一次
setValue的结果会覆盖之前所有的更新结果
以初始值{username:"Sam123",name:"Sam"}为例:
- 第一次遍历
username字段,生成的更新值为{username:"", name:"Sam"} - 第二次遍历
name字段,仍然基于原始初始值展开,生成的更新值为{username:"Sam123", name:""}
最终只有最后一个遍历到的name字段被置空,和预期结果不符。
修复方案
方案1:单次setState更新全量状态(推荐)
不需要循环多次调用setValue,直接构造完整的重置后状态,一次完成更新,性能更好也更易维护:
import { useState } from "react"; function useForm(initialfields) { const [value, setValue] = useState(initialfields); // 表单字段变更方法(原代码缺失的handleChange补全参考) const handleChange = (e) => { setValue(prev => ({ ...prev, [e.target.name]: e.target.value })) } const reset = () => { // 如果需求是重置为初始传入值,直接用下面这行即可 // setValue(initialfields); // 如果需求是所有字段置空,用reduce生成全空对象 const emptyState = Object.keys(value).reduce((res, key) => { res[key] = ""; return res; }, {}); setValue(emptyState); }; return [value, handleChange, reset]; } export default useForm;
注意:不要使用代码注释中直接修改原
value对象的写法,直接修改state不会触发React重渲染,属于违反React单向数据流规则的错误实现。
方案2:使用函数式更新获取最新状态
如果需要分步更新状态,给setValue传入更新函数,函数入参为上一次更新后的最新state,避免闭包捕获旧值的问题:
const reset = () => Object.keys(value).forEach((param) => setValue(prevValue => ({ ...prevValue, [param]: "" })) );
内容的提问来源于stack exchange,提问作者Sakchham Sangroula
相关产品推荐
相关产品推荐

