React中基于日期计算月度销售总额的代码优化问询
优化React Hook的月度销售统计代码(减少重复+支持每日总额统计)
我正在自学前端,写了一个React Hook用来计算图表需要的月度销售数据,功能正常但代码里有大量重复逻辑,想改成更简洁、易扩展的写法,同时还要新增每月每日总额统计的功能,返回包含每日数据的对象数组。
下面是我的现有代码、用法和返回示例:
现有代码
const month = (date) => new Date(date).toLocaleString('default', { month: 'long' }); export const useGetChartData = (orders) => { const orderTotal = orders.length const orderTotalsArray = orders.map(order => (+order.total) + (+order.total_tax)); const sumOrders = orderTotalsArray?.reduce((inc, a) => inc + a, 0); const getMonthFromDateAndTotals = orders?.map(order => ( { date: (order.date_paid ? month(order.date_paid) : month(order.date_modified)), total: +order.total + +order.total_tax })); const sendToChart = getMonthFromDateAndTotals.filter(o => o.total > 0); //filter! const January = sendToChart.filter((d) => d.date == 'January') const February = sendToChart.filter((d) => d.date == 'February') const March = sendToChart.filter((d) => d.date == 'March') const April = sendToChart.filter((d) => d.date == 'April') const May = sendToChart.filter((d) => d.date == 'May') const June = sendToChart.filter((d) => d.date == 'June') const July = sendToChart.filter((d) => d.date == 'July') const August = sendToChart.filter((d) => d.date == 'August') const September = sendToChart.filter((d) => d.date == 'September') const October = sendToChart.filter((d) => d.date == 'October') const November = sendToChart.filter((d) => d.date == 'November') const December = sendToChart.filter((d) => d.date == 'December') // const totalsPerMonths = [ //reduce! { month: 'January', total: January?.reduce((inc, a) => inc + a.total, 0) }, { month: 'February', total: February?.reduce((inc, a) => inc + a.total, 0) }, { month: 'March', total: March?.reduce((inc, a) => inc + a.total, 0) }, { month: 'April', total: April?.reduce((inc, a) => inc + a.total, 0) }, { month: 'May', total: May?.reduce((inc, a) => inc + a.total, 0) }, { month: 'June', total: June?.reduce((inc, a) => inc + a.total, 0) }, { month: 'July', total: July?.reduce((inc, a) => inc + a.total, 0) }, { month: 'August', total: August?.reduce((inc, a) => inc + a.total, 0) }, { month: 'September', total: September?.reduce((inc, a) => inc + a.total, 0) }, { month: 'October', total: October?.reduce((inc, a) => inc + a.total, 0) }, { month: 'November', total: November?.reduce((inc, a) => inc + a.total, 0) }, { month: 'December', total: December?.reduce((inc, a) => inc + a.total, 0) }, // ]; const dataVisualizationToChart = totalsPerMonths.filter(vd => vd.total > 0); return { dataVisualizationToChart, orderTotal, sumOrders }; };
用法示例
const { data: orders, isLoading: ordersLoading, errors: orderErrors} = useGetShopData("orders"); const { dataVisualizationToChart, sumOrders } = useGetChartData(orders)
现有返回结果
{ "dataVisualizationToChart": [ {"month": "February","total": 1875.96}, { "month": "March", "total": 1362.46}, { "month": "April","total": 66.05000000000004}, ], "orderTotal": 70, "sumOrders": 13064 }
优化后的解决方案
核心优化点
- 用对象分组替代重复filter:一次遍历完成按月份分组,避免每个月写重复的过滤逻辑
- 预定义月份数组保证顺序:确保输出的月度数据按全年顺序排列,不受对象键顺序影响
- 同时统计月度和每日总额:在分组过程中完成每日数据的累加,无需额外遍历
- 简化总和计算:直接在订单遍历中计算总销售额,减少中间数组的创建
优化后完整代码
const month = (date) => new Date(date).toLocaleString('default', { month: 'long' }); // 预定义全年月份,保证输出顺序 const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; export const useGetChartData = (orders = []) => { const orderTotal = orders.length; let sumOrders = 0; // 用对象存储分组数据:key是月份,value是{ total: 月度总额, daily: { 日期: 当日总额 } } const monthGroups = {}; // 初始化所有月份的分组结构 MONTHS.forEach(monthName => { monthGroups[monthName] = { total: 0, daily: {} }; }); // 遍历订单,完成分组、月度总额、每日总额、总销售额的计算 orders.forEach(order => { const orderTotalAmount = +order.total + +order.total_tax; if (orderTotalAmount <= 0) return; // 过滤无效数据 sumOrders += orderTotalAmount; const orderDate = order.date_paid || order.date_modified; const monthName = month(orderDate); const day = new Date(orderDate).getDate(); // 更新月度总额 monthGroups[monthName].total += orderTotalAmount; // 更新每日总额:如果当日已有数据则累加,否则初始化 monthGroups[monthName].daily[day] = (monthGroups[monthName].daily[day] || 0) + orderTotalAmount; }); // 转换为图表需要的月度数据格式,过滤总额为0的月份 const dataVisualizationToChart = MONTHS .map(monthName => ({ month: monthName, total: monthGroups[monthName].total })) .filter(item => item.total > 0); // 转换为包含每日数据的月度数组(新增需求) const dailyMonthTotals = MONTHS .map(monthName => ({ month: monthName, total: monthGroups[monthName].total, daily: Object.entries(monthGroups[monthName].daily).map(([day, total]) => ({ day: Number(day), total })) })) .filter(item => item.total > 0); return { dataVisualizationToChart, dailyMonthTotals, // 新增的每日总额数据 orderTotal, sumOrders }; };
优化后返回结果示例
{ "dataVisualizationToChart": [ {"month": "February","total": 1875.96}, {"month": "March", "total": 1362.46}, {"month": "April","total": 66.05000000000004} ], "dailyMonthTotals": [ { "month": "February", "total": 1875.96, "daily": [ {"day": 5, "total": 450.2}, {"day": 12, "total": 1425.76} ] }, { "month": "March", "total": 1362.46, "daily": [ {"day": 3, "total": 890.5}, {"day": 18, "total": 471.96} ] } ], "orderTotal": 70, "sumOrders": 13064 }
内容的提问来源于stack exchange,提问作者FZDEV
相关产品推荐
相关产品推荐

