You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 14:54:24