React中使用过滤器计算总收入时出现NaN问题求助
React过滤后计算总收入返回NaN的问题修复
问题梳理
在React应用中,尝试根据发行商过滤器计算歌曲总收入时出现NaN值,且过滤器逻辑、组件绑定、金额计算逻辑均存在错误,导致无法实现过滤后显示正确总金额的功能。
错误点分析
过滤器逻辑混乱
- 错误将数字类型的
totalRevenue与空字符串比较,totalRevenue === ""永远为false,导致过滤条件失效 - 错误访问
song.Distributor?.Revenue,Revenue是song的直接属性,并非Distributor的子属性 - 逻辑或位置错误,错误将两个匹配条件写在同一个
includes参数中
- 错误将数字类型的
Select组件绑定错误
- Select的value错误绑定
filterDistributor || totalRevenue,该组件仅用于选择发行商,应仅绑定filterDistributor - onChange事件错误尝试同时更新
filterDistributor和totalRevenue,totalRevenue是计算结果,不应通过选择器直接修改
- Select的value错误绑定
总收入计算未关联过滤结果
原代码仅基于原始songs数组计算总收入,未使用过滤后的歌曲列表,导致过滤后总金额不更新金额格式化精度丢失
Math.round(totalRevenue).toFixed(2)会先将金额取整再保留两位小数,丢失小数部分精度
修正后的完整代码
import { useState, useEffect } from 'react'; const RevenueTable = ({ songs }) => { const [filterDistributor, setFilterDistributor] = useState(""); // 分页相关状态(保留原有逻辑) const [songsPerPage] = useState(10); const [currentPage, setCurrentPage] = useState(1); const pagesVisited = (currentPage - 1) * songsPerPage; // 先计算过滤后的歌曲列表 const filteredSongs = songs.filter((song) => { if (filterDistributor === "") return true; return song.Distributor?.toLowerCase().includes(filterDistributor.toLowerCase()); }); // 根据过滤后的歌曲计算总收入 const [totalRevenue, setTotalRevenue] = useState(0); useEffect(() => { const total = filteredSongs.reduce((acc, song) => { const revenue = typeof song.Revenue === 'number' ? song.Revenue : Number(song.Revenue); return isNaN(revenue) ? acc : acc + revenue; }, 0); setTotalRevenue(total); }, [filteredSongs]); // 分页处理后的展示列表 const displaySongs = filteredSongs .slice(pagesVisited, pagesVisited + songsPerPage) .map((song) => ( <tr key={song.id} className="font-medium bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600"> <td className="py-2 px-4 text-left">{song.Distributor}</td> <td className="py-2 px-4 text-left">{song.Revenue.toFixed(4)}</td> </tr> )); return ( <div> <div className="flex w-full"> <select id="Labels" className="bg-slate-900 text-white border border-gray-500 text-sm focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" value={filterDistributor} onChange={(e) => setFilterDistributor(e.target.value)} > <option value="">Choose a Distributor</option> {[...new Set(songs.map((song) => song.Distributor))].map((distributor) => ( <option key={distributor} value={distributor}> {distributor} </option> ))} </select> </div> <div className="w-96 p-6 my-10 gap-4 shadow-md rounded-md bg-slate-900 text-center"> <p className="font-normal text-white dark:text-gray-400"> Total Revenue: </p> <p className="text-2xl font-bold tracking-tight text-white dark:text-white"> {(Math.round(totalRevenue * 100) / 100).toFixed(2)} € </p> </div> {/* 完整表格结构 */} <table className="w-full text-sm text-left text-gray-500 dark:text-gray-400"> <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"> <tr> <th className="py-3 px-4">Distributor</th> <th className="py-3 px-4">Revenue</th> </tr> </thead> <tbody> {displaySongs} </tbody> </table> </div> ); }; export default RevenueTable;
关键修正说明
分离过滤与计算逻辑
- 先生成
filteredSongs过滤列表,确保过滤逻辑独立清晰 - 总收入计算依赖
filteredSongs,过滤条件变化时自动重新计算总金额
- 先生成
修复过滤器逻辑
- 移除无效的
totalRevenue === ""判断,仅保留发行商匹配逻辑 - 正确访问
song.Revenue属性
- 移除无效的
修正Select组件绑定
- Select仅绑定
filterDistributor状态,onChange仅更新该状态
- Select仅绑定
优化金额处理
- 先判断Revenue类型,避免不必要的类型转换
- 使用
(Math.round(totalRevenue * 100) / 100).toFixed(2)保证两位小数的精度
符合React规范
- 列表渲染添加
key={song.id}属性
- 列表渲染添加
内容的提问来源于stack exchange,提问作者user12220646
相关产品推荐
相关产品推荐

