为何useEffect仅执行一次?info状态更新次数少于预期的原因
问题原因与解决方案
核心问题1:状态更新异步性+闭包陷阱
你在fetchData里调用setLoanAmount(loan)和setCollectedAmount(collected)后,直接用loanAmount和collectedAmount构造info对象——但React状态更新是异步的,这两个变量此时还是更新前的旧值,不是你刚从接口拿到的loan和collected。更关键的是,循环里两次调用fetchData时,都通过闭包捕获到了初始的空info数组。
核心问题2:异步操作的状态竞争
for循环里连续触发两次异步的fetchData,两个函数都会基于初始空数组执行setInfo([...info, newItem]),导致第二次更新直接覆盖第一次的结果,最终info里只会留下最后一个项,看起来更新次数少了1次。
修复方案
直接使用await返回的原始值,同时用函数式更新获取最新的info状态,彻底规避闭包问题:
const fetchData = async function (contractAddress) { setContractAddress(contractAddress) const loan = await readLoanAmount({"address": contractAddress}); setLoanAmount(loan) const collected = await readCollectedAmount({"address": contractAddress}); setCollectedAmount(collected); // 函数式更新,prevInfo始终是当前最新的info状态 setInfo(prevInfo => [...prevInfo, { "contractAddress": contractAddress, "loanAmount": loan, // 直接用await拿到的原始值,不用状态变量 "collectedAmount": collected }]) }
额外优化:移除不必要的状态(可选)
如果loanAmount和collectedAmount只是临时存储当前合约数据、不用于页面渲染,完全可以去掉这两个状态,减少无效的状态更新:
const fetchData = async function (contractAddress) { setContractAddress(contractAddress) const loan = await readLoanAmount({"address": contractAddress}); const collected = await readCollectedAmount({"address": contractAddress}); setInfo(prevInfo => [...prevInfo, { "contractAddress": contractAddress, "loanAmount": loan, "collectedAmount": collected }]) }
循环异步操作稳定性优化(可选)
如果需要确保所有异步请求完成后统一更新状态,避免多次零散更新,可以用Promise.all批量处理:
useEffect(() => { checkWalletIsConnected(); fetch('http://localhost:5000/loanContract/getloanContracts') .then(response => response.json()) .then(async data => { // 并行执行所有请求,收集结果 const infoItems = await Promise.all(data.map(async item => { const ca = item.contractAddress; setContractAddress(ca); // 不需要实时更新的话可移除 const loan = await readLoanAmount({"address": ca}); const collected = await readCollectedAmount({"address": ca}); return { contractAddress: ca, loanAmount: loan, collectedAmount: collected }; })); // 一次性更新info状态 setInfo(prevInfo => [...prevInfo, ...infoItems]); }) .catch(err => { console.log(err.message); }); }, []);
内容的提问来源于stack exchange,提问作者aymane igmiden
相关产品推荐
相关产品推荐

