JSX点击事件多函数调用问题:loadData需二次点击生效
问题原因
React的useState更新是异步批量处理的,saveData中调用setSavedImageData(dataURL)后,savedImageData不会立刻更新。当multiFunc里紧接着执行loadData时,读取的还是更新前的null值,导致第一次点击无效果;第二次点击时savedImageData已完成更新,才能正常执行。
解决方案
方案一:直接传递数据(推荐)
既然saveData里已经生成了dataURL,直接把这个值传给loadData,跳过对savedImageData state的依赖:
const [savedImageData, setSavedImageData] = useState(null); const saveData = async () => { if (canvasRef.current) { const canvas = canvasRef.current; const dataURL = canvas.toDataURL(); setSavedImageData(dataURL); setStore(prevStore => [...prevStore, dataURL]); console.log(dataURL); console.log('data saved'); return dataURL; // 返回生成的dataURL } return null; }; const clearData = () => { const canvas = canvasRef.current const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); console.log('data cleared ') return true }; const loadData = (data) => { // 接收传入的数据 if (data) { setImageUrl(data); console.log(data) setIsRetrieveData(true); setIsDrawing(false); console.log('data loaded ') } }; const multiFunc = async () => { const dataURL = await saveData(); // 等待saveData返回结果 clearData(); loadData(dataURL); // 直接传递数据给loadData };
方案二:用useEffect监听state变化
如果必须依赖savedImageData的state更新,可以通过额外的触发状态,让useEffect在state更新后自动执行loadData:
const [savedImageData, setSavedImageData] = useState(null); const [triggerLoad, setTriggerLoad] = useState(false); // 监听savedImageData和triggerLoad的变化 useEffect(() => { if (triggerLoad && savedImageData) { loadData(); setTriggerLoad(false); // 重置触发状态 } }, [savedImageData, triggerLoad]); const saveData = async () => { if (canvasRef.current) { const canvas = canvasRef.current; const dataURL = canvas.toDataURL(); setSavedImageData(dataURL); setStore(prevStore => [...prevStore, dataURL]); console.log(dataURL); console.log('data saved'); } }; const clearData = () => { const canvas = canvasRef.current const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); console.log('data cleared ') return true }; const loadData = () => { if (savedImageData) { setImageUrl(savedImageData); console.log(savedImageData) setIsRetrieveData(true); setIsDrawing(false); console.log('data loaded ') } }; const multiFunc = async () => { await saveData(); // 等待state更新进入队列 clearData(); setTriggerLoad(true); // 触发loadData执行 };
方案说明
- 方案一逻辑更直接,完全避开了state异步更新的问题,性能更优,优先推荐。
- 方案二更适合需要基于state更新联动其他复杂逻辑的场景。
内容的提问来源于stack exchange,提问作者willd
相关产品推荐
相关产品推荐

