React中点击提交按钮时如何保证useState存储的值为最新数据
根因分析
提交旧状态问题核心不是useState异步更新导致的,而是闭包捕获问题:
你用空依赖的useEffect仅在组件首次渲染时将saveDisplayedVideo函数挂载到childRef上,这个函数捕获了首次渲染时的displayedVideoDataList、videoDataList初始值。后续组件状态更新后,重新生成的saveDisplayedVideo函数不会同步更新到childRef中,所以调用保存函数时永远拿到的是初始状态值。
正常用户交互(比如拖拽完成后间隔一段时间再点击保存)时,useState的批处理更新早就执行完成,状态已经是最新的,只要能拿到最新的状态引用就不会出现旧数据问题。
可行解决方案
方案1:更新ref绑定逻辑,保持函数为最新版本(推荐,改动最小)
用useCallback包裹保存函数,关联对应状态作为依赖项,再修改useEffect的依赖项为包裹后的保存函数,保证ref中始终绑定最新版本的保存函数:
import { useCallback } from 'react'; // 用useCallback包裹,依赖项为函数内用到的所有状态 const saveDisplayedVideo = useCallback(async () => { const jsonData = JSON.parse(JSON.stringify(displayedVideoDataList)); console.log(jsonData); console.log(displayedVideoDataList); console.log(videoDataList); // 补充提交后端的逻辑即可 }, [displayedVideoDataList, videoDataList]); // useEffect添加saveDisplayedVideo作为依赖,函数更新时同步刷新ref useEffect(()=>{ props.childRef.current = saveDisplayedVideo; }, [saveDisplayedVideo]);
方案2:用ref同步最新状态,提交时直接从ref取值
如果不想频繁更新ref绑定的函数,可以单独用ref存储最新的状态值,状态更新时自动同步到ref,保存函数直接从ref取数即可:
import { useRef } from 'react'; const [videoDataList, setVideoDataList] = useState(props.videoData); const [displayedVideoDataList, setDisplayedVideoDataList] = useState([]); // 新增ref存储最新状态 const latestStateRef = useRef({ videoDataList, displayedVideoDataList }); // 状态更新时同步到ref useEffect(() => { latestStateRef.current = { videoDataList, displayedVideoDataList }; }, [videoDataList, displayedVideoDataList]); // 保存函数直接从ref取最新值,不需要依赖状态 async function saveDisplayedVideo(){ const { videoDataList, displayedVideoDataList } = latestStateRef.current; const jsonData = JSON.parse(JSON.stringify(displayedVideoDataList)); console.log(jsonData); console.log(displayedVideoDataList); console.log(videoDataList); } // 这里useEffect可以保持空依赖不变 useEffect(()=>{ props.childRef.current = saveDisplayedVideo; },[]);
方案3:同事件回调内提交直接用计算的新值(仅适用于状态更新和提交在同一回调的场景)
如果你的状态更新和提交操作在同一个事件回调中触发,可以不用等待useState更新,直接用你计算出来的新值提交,比如:
// 示例逻辑,你的拖拽+延时提交的场景不适用该方案 function handleToggleAndSubmit() { const newStatus = !status; setStatus(newStatus); // 直接用新计算的newStatus提交,不需要依赖state submitData(newStatus); }
内容的提问来源于stack exchange,提问作者JunHui Li
相关产品推荐
相关产品推荐

