React中通过className求和显示NaN问题排查求助
解决通过className求和显示NaN的问题
问题背景
尝试通过className获取页面上的数值元素并求和展示,但结果始终显示NaN,原代码如下:
原求和逻辑代码
let hoursCompleted = document.getElementsByClassName('data-legend-info-part'); let totalHoursCompleted = []; for (let i = 0; i < hoursCompleted.length; i++) { const hours = hoursCompleted[i]; totalHoursCompleted.push(Number(hours)); } let sum = 0; for (let i = 0; i < totalHoursCompleted.length; i++) { sum += totalHoursCompleted[i]; }
原React渲染代码
return ( <div className="pie-chart-wrapper"> <div id={`pie-chart-container-${pieChartId}`} className="pie-chart" /> <div> <div className="pie-chart-legend-header"> <div>Name</div> <div>{dataLegendHeader}</div> </div>{/*Values for Name Header entered here*/} {Object.keys(dataLegend).map(key => ( <div key={key} className="pie-chart-legend-item"> <div className="data-legend-color" style={{ backgroundColor: color(key) }} /> <div className="data-legend-info"> {dataLegend[key].map(legendPart => ( <div className="data-legend-info-part">{legendPart}</div> ))} </div> </div> ))}{/*Values for Hours Header entered here*/} <div className="pie-chart-legend-item"> <div className="data-legend-info"> Total Hours Worked: <div className="data-legend-info-part">{sum}</div> </div> </div> </div> </div> );
期望效果:若有3个各4小时的任务,sum应显示12。
错误原因
- DOM元素直接转数字:代码中
Number(hours)的hours是DOM元素对象,并非元素内的文本内容,转换后直接得到NaN。 - DOM操作时机错误:若在组件渲染完成前调用
document.getElementsByClassName,此时DOM尚未生成,获取到的元素列表为空,求和自然出错。 - React反模式:直接从DOM提取数据不符合React的数据流理念,数据源
dataLegend才是数据的唯一可信来源。
解决方法
方法1:从数据源直接计算(推荐,符合React设计模式)
直接遍历dataLegend计算总和,无需操作DOM,代码简洁且避免异步问题:
// 遍历数据源累加所有小时数 const sum = Object.values(dataLegend).reduce((total, legendParts) => { return total + legendParts.reduce((partTotal, part) => { // 处理非数字情况,转换失败时取0避免NaN return partTotal + (Number(part) || 0); }, 0); }, 0);
方法2:修正DOM操作方式(不推荐,仅作参考)
若必须通过DOM获取,需确保在组件渲染完成后执行,使用useEffect监听数据源变化:
import { useEffect, useState } from 'react'; function YourComponent(props) { const [sum, setSum] = useState(0); const { dataLegend } = props; useEffect(() => { let total = 0; const elements = document.getElementsByClassName('data-legend-info-part'); for (let elem of elements) { // 获取元素文本并转数字,处理无效值 const value = Number(elem.textContent.trim()); total += isNaN(value) ? 0 : value; } setSum(total); }, [dataLegend]); // 数据源变化时重新计算 // 后续渲染代码不变 return ( // ... 原渲染内容 ); }
内容的提问来源于stack exchange,提问作者Shaun Sullivan
相关产品推荐
相关产品推荐

