使用useState无法正确更新文件状态的问题排查与修复
文件选择器状态管理异常问题修复
我希望通过以下代码实现文件选择器选择文件,并将选中的文件作为组件状态进行管理,但运行后出现注释中描述的输出结果,不清楚问题原因,请问该如何修复?
const [file, setFile] = useState<File | null>(null); const fileSelect = (event: ReactChangeEvent<HTMLInputElement>) => { if (event.target.files === null) { return ; } const f: File | null = event.target.files[0]; console.log(typeof(f)); // <- object setFile(f); console.log(f); // <- null } return ( <div className="flex px-1"> <input onChange={fileSelect} type="file" /> </div> );
问题原因
这是React合成事件的池化机制导致的:React会复用合成事件对象,在事件处理函数执行完毕后,会清空事件对象的所有属性。你定义的f是对event.target.files[0]的引用,当事件函数执行到最后的console.log(f)时,原事件对象已经被重置,所以这个引用指向的内容变成了null。
修复方案
有两种简单的解决方式:
方案1:阻止事件对象被回收
调用event.persist()可以让React保留当前事件对象,不将其放回事件池:
const fileSelect = (event: ReactChangeEvent<HTMLInputElement>) => { event.persist(); // 新增这一行 if (event.target.files === null) { return ; } const f: File | null = event.target.files[0]; console.log(typeof(f)); setFile(f); console.log(f); }
方案2:克隆File对象
直接创建一个新的File对象,脱离对原事件对象的依赖:
const fileSelect = (event: ReactChangeEvent<HTMLInputElement>) => { if (event.target.files === null) { return ; } const originalFile = event.target.files[0]; // 克隆File对象 const f = new File([originalFile], originalFile.name, { type: originalFile.type }); console.log(typeof(f)); setFile(f); console.log(f); }
内容的提问来源于stack exchange,提问作者musako
相关产品推荐
相关产品推荐

