React中window.confirm回调内useState存储的上传文件状态被清空问题
问题原因
这是React的闭包陷阱导致的:
- 你的
useEffect仅将halfFilledForm作为依赖项,仅当halfFilledForm发生变化时,这个effect才会重新执行 - effect执行时会捕获当前作用域内的所有状态值,你首次执行effect时
files还是初始的空数组[] - 后续你调用
setFiles更新文件列表时,只要halfFilledForm没有变化,effect就不会重新运行,history.block绑定的回调永远引用的是首次执行时捕获的旧files值,所以打印出来一直是空数组。
解决方案
方案1:把files加入useEffect的依赖数组
每次files更新时,effect都会重新执行,重新注册最新的history.block回调,就能拿到最新的files值,代码修改如下:
useEffect(() => { if (halfFilledForm) { const unblock = history.block((_) => { if (window.confirm("Do you want to save the Story Idea as Draft?")) { console.log(files) // 可以拿到最新的files saveAsDraft(); } return true; }); return () => { unblock(); }; } // 把files加入依赖数组 }, [halfFilledForm, files]);
方案2:用useRef存储最新的files状态
useRef的current属性是可变的,不受闭包限制,可以随时拿到最新值:
const [files, setFiles] = useState([]); // 新增ref同步files的最新值 const filesRef = useRef(files); // 监听files变化,自动更新ref useEffect(() => { filesRef.current = files; }, [files]); // 原来的history.block useEffect不用改依赖,回调里读ref即可 useEffect(() => { if (halfFilledForm) { const unblock = history.block((_) => { if (window.confirm("Do you want to save the Story Idea as Draft?")) { console.log(filesRef.current) // 直接读ref的current拿到最新值 saveAsDraft(); } return true; }); return () => { unblock(); }; }}, [halfFilledForm]);
方案3:将saveAsDraft改造为接收files作为入参
如果saveAsDraft逻辑允许,你可以在调用时主动把最新的files作为参数传入,配合上述两种方案使用即可。
内容的提问来源于stack exchange,提问作者Lokesh Bajracharya
相关产品推荐
相关产品推荐

