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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:04:52