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

React中dictionary打印正常取值返回undefined及state更新问题

问题定位与修复方案

核心问题1:map回调无返回值导致state更新为undefined

你代码中setBuys对应的map逻辑里,用花括号包裹了返回对象但没有写return语句,此时花括号会被识别为函数体块,map遍历每一项都会返回undefined,最终state会被更新为全undefined的数组,自然无法读取到预期值。
原错误代码:

setBuys(
    buys.map(
        b => {
            {...b, ...newDictionary[b.asset]}
        }
    )
)

修复方式:用括号包裹对象实现隐式返回,或手动添加return语句:

setBuys(
    buys.map(
        b => ({...b, ...newDictionary[b.asset]})
    )
)

核心问题2:useEffect无依赖数组导致定时器重复创建

当前useEffect没有传入第二个依赖参数,会在每次组件渲染完成后都执行,每次运行都会创建新的60s定时器,最终会出现大量重复请求,还会引发内存泄漏。
修复方式:给useEffect添加依赖数组,若buys不会动态变化就传空数组,仅在组件挂载时执行一次;若buys会动态更新就把buys加入依赖数组,每次buys变化时自动销毁旧定时器、创建新定时器:

useEffect(() => {
  // 原有逻辑
}, []) // 空依赖仅挂载执行一次,buys可变时改为[buys]

核心问题3:闭包捕获旧state导致更新异常

你在setBuys时直接使用了当前作用域下的buys变量,这个变量是useEffect运行时捕获的旧值,如果buys之前发生过变更,会基于旧值更新,出现状态不同步问题。
修复方式:使用setState的函数式更新语法,永远拿到最新的state值:

setBuys(prevBuys => 
  prevBuys.map(b => ({...b, ...newDictionary[b.asset]}))
)

补充说明(早期异步map读取空的原因)

你最开始没有使用Promise.all的版本,直接执行buys.map(async buy => {})时,返回的是Promise数组,所有异步请求还未执行完成你就立刻读取newDictionary,此时对象还是空的。浏览器控制台打印的对象是引用类型,后续异步完成填充后你展开控制台才会看到值,实际同步读取时没有内容,你后续改用Promise.all等待所有异步完成再处理是正确的写法。

完整修复后的代码

useEffect(() => {
    const refreshData = async() => {
        const d = await Promise.all(
            buys.map(async buy => {
                const data = await queryCoinGeckoAPI(buy);
                const market_price = data.market_data.current_price.aud;
                const price_change = data.market_data.price_change_24h_in_currency.aud;
                const price_change_percentage = data.market_data.price_change_percentage_24h_in_currency.aud;
                const profit = buy.units === 0 || buy.price === 0 ? 0 : market_price * buy.units - buy.price;
                return {
                    asset: buy.asset,
                    market_price,
                    price_change,
                    price_change_percentage,
                    profit
                };
            })
        )

        const newDictionary = Object.fromEntries(d.map(item => [item.asset, item]));

        setBuys(prevBuys => 
            prevBuys.map(b => ({...b, ...newDictionary[b.asset]}))
        )
    }
    const interval = setInterval(refreshData, 60000);
    // 组件挂载先执行一次,无需等待60秒
    refreshData();
    return () => clearInterval(interval);
}, [buys])

内容的提问来源于stack exchange,提问作者foo.d

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:15:04