React useState动态对象赋值变NaN:时序数据求和异常求助
问题分析与修复方案
核心问题
你遇到的NaN问题主要来自两个关键点:
- React状态更新的异步特性:循环中多次调用
setTotalHours时,闭包捕获的是旧的totalHours状态值(初始为空或未更新的旧值),而非实时更新后的状态,导致累加逻辑错误。 - 初始值处理与重复累加:空对象的
total[key]为undefined,直接做加法会生成NaN;同时原代码最后重复处理currHourTotal,导致数值被重复累加。
修复代码(推荐方案)
重构逻辑,先一次性计算所有小时的累加总和,再批量更新状态,避免异步更新带来的闭包问题:
const [totalHours, setTotalHours] = useState<{[key: string]: number}>({}); useEffect(() => { if (!loading && hours.length > 0) { // 按小时分组,确保每个小时的统计值只保留一次 const hourStatsMap = new Map<number, typeof hours[0]['meta']>(); for (const h of hours) { const hour = new Date(h.timestamp).getUTCHours(); if (h.meta) { hourStatsMap.set(hour, h.meta); } } // 计算所有状态的总累加时长(转换为小时,保留两位小数) const finalTotal: {[key: string]: number} = {}; for (const meta of hourStatsMap.values()) { for (const key in meta) { const hourValue = Number((meta[key] / (1000 * 60 * 60)).toFixed(2)); finalTotal[key] = (finalTotal[key] || 0) + hourValue; } } // 一次性更新状态 setTotalHours(finalTotal); console.log('Total State', finalTotal); } }, [loading, hours]);
若需保留循环流式更新(备选方案)
如果必须在循环中逐步更新状态,必须使用函数式更新,确保每次都基于最新的状态计算:
// 替换原循环中的setTotalHours调用部分 setTotalHours(prevState => { const updatedState = {...prevState}; for (const key in h.meta) { const hourValue = Number((currHourTotal[key] / (1000 * 60 * 60)).toFixed(2)); // 处理初始值,避免undefined + number生成NaN updatedState[key] = (updatedState[key] || 0) + hourValue; } return updatedState; });
额外注意事项
- 原代码中
currHourTotal直接赋值会覆盖同小时的之前值,若你的hours数组中每个元素是小时内的分段统计而非小时总计,需要改为累加逻辑(currHourTotal[key] = (currHourTotal[key] || 0) + h.meta[key])。 - 注意处理
hours为空的边界情况,避免hours[0]报错。
内容的提问来源于stack exchange,提问作者matthewholden01
相关产品推荐
相关产品推荐

