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

React动态列日期工时表:如何匹配数据到对应日期列

问题描述

我正在开发一款用于展示用户当月每日对应工时的表格组件,由于不同月份天数存在差异,表格列需要动态生成。目前已经完成基础结构搭建:表头可根据选中的年、月展示对应数量的日期列,也可以正常通过API拉取数据,但始终无法将数据中的日期与表格的日期列做正确匹配。
我制作了简化版示例展示当前开发进度,示例中保留了核心逻辑。
实际业务场景下,我使用的数据包含两个日期对象:开始时间与结束时间。通常工时记录不会跨天,但也存在跨天的可能性,当前表格开发阶段我先仅提取开始时间对应的日期做匹配,这也是示例代码中仅保留start字段的原因。
我曾尝试通过如下逻辑提取工时记录对应的当月日期:

setDataDates(
   const dataDay = new Date(data.start).getDate()
)

但提取到日期后,我不清楚如何将对应工时渲染到表格中正确的日期列下,寻求开发指导。


问题更新

我一度以为已经接近实现,至少页面可以正常渲染,但示例抛出了错误:Objects are not valid as a React child (found: object with keys {day}),报错位置在表头遍历渲染日期的部分。这部分逻辑之前是可以正常运行的,我一开始没定位到出错原因,后来发现是我将数组元素改成了{key: value}结构,map遍历时没有取day.day属性,该问题已经修复,代码已同步更新。
但目前核心的日期数据匹配功能仍然无法正常运行,当前代码如下:

import "./styles.css";
import React from "react";

export default function App() {
  const data = [
    {
      start: "2022-04-02",
      hours: 2
    },
    {
      start: "2022-04-06",
      hours: 3
    },
    {
      start: "2022-04-11",
      hours: 1
    }
  ];
  const [newData, setNewData] = React.useState();

  const setDataforTable = () => {
    const oldData = data.map((data) => ({
      day: new Date(data.start).getDate(),
      hours: data.hours
    }));
    console.log("newData", oldData);
    setNewData(oldData);
  };

  const [days, setDays] = React.useState([]);

  const settingDays = () => {
    const daysInMonth = 30;

    let dayInfo = [];
    for (let i = 1; i <= daysInMonth; i++) {
      dayInfo.push(i);

     let result = dayInfo.map((i) => (
       {
        day: i
      }
      ));
      console.log("day ", result);
      setDays(result);
      
    }
  };

  const totalHours = data.map((i) => i.hours).reduce((a, b) => a + b, 0);

  let tableDisplay;


  if (days !== []) {
    
    tableDisplay = (
      <div>
        <table>
          <thead>
            <tr>
              <th> Date </th>
              {days && days.map((day) => <th key={day}>{day.day}</th>)}
              <th>Total Hours</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Hours</td>
              {newData && newData.map((d) => 
              <td key={d.day}>{d.day === days.day ? d.hours : 0}</td>
              )}
              <td>{totalHours}</td>
            </tr>
          </tbody>
        </table>
      </div>
    );
  }

  return (
    <div>
      <button
        onClick={() => {
          setDataforTable(), settingDays();
        }}
      >
        Click
      </button>
      {tableDisplay}
    </div>
  );
}

问题根因与解决方法

核心问题是单元格遍历逻辑写反了:表格列数和当月天数一致,所以渲染表体单元格时要遍历生成好的日期数组,而不是遍历工时数据数组——工时数据的长度和当月天数绝大多数情况不相等,自然没法对齐到所有列。
除此之外代码里还有几个逻辑问题需要同步修正:

  • 数组判断逻辑错误:days !== []永远为真,JS中数组是引用类型,两个空数组比较不会相等,直接判断days.length即可
  • settingDays函数里不需要在for循环内部反复执行map和setDays,循环生成完所有日期后一次赋值即可
  • 日期匹配时,days是数组,不存在days.day属性,需要针对每个遍历到的日期列,去工时数据里找对应日期的工时值,找不到就显示0
  • 计算总工时的时候不要直接用原始data计算,要兼容后续动态拉取的接口数据

可以按照以下思路调整逻辑:

  1. 生成日期列:直接生成1到当月天数的数组即可,不需要额外包{day: i}的结构,减少取值错误
  2. 预处理工时数据:提前把工时数据转成{日期: 工时}的对象结构,匹配的时候不需要每次遍历数组找值,性能更好
  3. 渲染单元格:遍历日期数组,对每个日期,从处理好的工时映射里取对应值,没有就显示0

参考修正代码:

import "./styles.css";
import React from "react";

export default function App() {
  // 原始接口数据
  const data = [
    { start: "2022-04-02", hours: 2 },
    { start: "2022-04-06", hours: 3 },
    { start: "2022-04-11", hours: 1 }
  ];

  const [hoursMap, setHoursMap] = React.useState({});
  const [days, setDays] = React.useState([]);
  const [totalHours, setTotalHours] = React.useState(0);

  const initTableData = () => {
    // 1. 生成当月日期列,这里示例固定30天,实际业务中可以根据选中年月动态计算当月天数
    const daysInMonth = 30;
    const dayList = Array.from({length: daysInMonth}, (_, i) => i+1);
    setDays(dayList);

    // 2. 处理工时数据,转成 日期:工时 的映射结构,方便匹配
    const map = {};
    let total = 0;
    data.forEach(item => {
      const day = new Date(item.start).getDate();
      map[day] = item.hours;
      total += item.hours;
    })
    setHoursMap(map);
    setTotalHours(total);
  };

  return (
    <div>
      <button onClick={initTableData}>
        加载表格
      </button>
      {days.length > 0 && (
        <table>
          <thead>
            <tr>
              <th>分类</th>
              {days.map(day => <th key={day}>{day}日</th>)}
              <th>总工时</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>工时</td>
              {/* 遍历日期列,逐列匹配工时 */}
              {days.map(day => <td key={day}>{hoursMap[day] || 0}</td>)}
              <td>{totalHours}</td>
            </tr>
          </tbody>
        </table>
      )}
    </div>
  );
}

如果后续要支持跨天工时,只需要在处理hoursMap的时候,根据开始、结束时间计算覆盖的所有日期,按规则拆分工时到对应日期即可,当前的表格渲染逻辑不需要改动。


内容的提问来源于stack exchange,提问作者Jowz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:18:33