React setState异步特性导致首次点击console.log无数据问题排查
React setState异步导致的控制台打印延迟问题
问题代码
import React from "react"; import Button from "./Button"; import Section from "./Section"; import { Dragendrop } from "./Dragendrop"; export const RightBox = () => { const [fileData, setFileData] = React.useState(); const [data, setData] = React.useState(null); const [recieverAddress, setReceiverAddress] = React.useState(""); const handleFileData = (data) => { setFileData(data); }; const upload = () => { if (fileData.length > 0) { const reader = new FileReader(); reader.onload = function (fileEvent) { const f = fileEvent.target.result; setData(f); console.log(data); }; reader.readAsDataURL(fileData[0]); } }; const checkUser = () => { }; return ( <div className="w-1/2 h-[45rem] mb-5 bg-stone-900 p-2 rounded-md"> <div className="flex gap-2"> <input type="text" onChange={(e) => { setReceiverAddress(e.target.value); }} className="w-full p-3 font-code rounded-md" placeholder="Reciever Id" /> <Button onClick={checkUser}>Check</Button> </div> <Section className="w-full h-[580px] -mx-2 my-3" crosses customPaddings id="data" > <div className="container"> <Dragendrop onFileData={handleFileData} /> </div> </Section> <div className="w-full"> <Button onClick={upload} className="w-full content-end flex"> Send </Button> </div> </div> ); };
问题描述
点击Send按钮触发upload函数后,首次点击控制台无数据输出,第二次点击才会打印文件数据,请问这是什么原因?如何实现首次点击就打印数据?
原因分析
这是因为React的setState是异步操作——调用setData(f)后,组件的data状态不会立刻更新,你紧接着执行的console.log(data)读取的还是更新前的旧值。第二次点击时,data已经是上一次更新后的结果,所以能打印出来。
解决方案
方法一:直接打印读取到的文件数据
既然f就是你要存入state的最新值,直接打印它即可,无需等待state更新:
reader.onload = function (fileEvent) { const f = fileEvent.target.result; setData(f); console.log(f); // 直接打印f,而非data };
方法二:用useEffect监听state变化
如果必须要在state更新完成后执行打印,可以用useEffect监听data的变化,当data更新时触发打印:
import React, { useEffect } from "react"; // 先引入useEffect // ... 其他代码保持不变 useEffect(() => { if (data !== null) { console.log(data); } }, [data]); // 依赖数组传入data,仅当data变化时执行回调 const upload = () => { if (fileData.length > 0) { const reader = new FileReader(); reader.onload = function (fileEvent) { const f = fileEvent.target.result; setData(f); // 此处无需再执行console.log }; reader.readAsDataURL(fileData[0]); } };
内容的提问来源于stack exchange,提问作者Bhowmik Chawda
相关产品推荐
相关产品推荐

