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

React日历JavaScript Date异常 周重复首周丢失问题排查修复

问题原因
  • 周起始计算逻辑错误:你以周一为每周第一天,但原偏移公式startDate.getDate() - startDate.getDay() + 1未单独处理周日场景:JS中getDay()返回0代表周日,此时公式会给日期+1直接跳到下周一,导致包含当月1号的首周被直接跳过。
  • 循环终止逻辑漏洞:仅通过getMonth()/getFullYear()大小判断是否超出当月,未考虑月份值0-11循环的特性:跨年场景下上年12月的月份值为11,大于当年1月的月份值0,会误将跨上年的首周判定为超出范围直接截断;同时该判断也无法正确覆盖月末跨月周的边界场景。
  • 列表缺失稳定唯一key:所有循环渲染的SingleWeek、SingleDay组件都未传入key属性,React在虚拟DOM调和阶段会错误复用组件节点,这就是你观察到「push组件前打印日期完全正确、组件内部拿到props不符合预期、第二周重复渲染」的核心原因。
修复方案
  • 修正周起始偏移逻辑:单独处理周日的偏移值,确保所有周都从周一开始
  • 替换终止判断逻辑:先计算当月最后一天的时间戳,当周起始日期超过当月最后一天时终止循环,彻底解决跨月、跨年的边界判断错误
  • 给所有列表项添加基于日期时间戳的稳定唯一key,避免React组件复用错误
  • 日期计算时统一基于新Date实例操作,规避JS Date作为引用类型被意外修改的隐性问题
修复后代码

整月日期生成函数

function getWholeMonth(curDate) {
  const ans = [];
  const focusDate = new Date(curDate);
  // 重置为当月1号
  focusDate.setDate(1);
  // 计算当月最后一天:下个月第0天即为当月最后一天
  const lastDayOfMonth = new Date(focusDate.getFullYear(), focusDate.getMonth() + 1, 0);
  
  // 计算首周的周一日期
  const startDate = new Date(focusDate);
  const weekDay = startDate.getDay();
  // 周日特殊处理:减6天回到上周一,其余日期减(weekDay-1)回到当周周一
  const mondayOffset = weekDay === 0 ? 6 : weekDay - 1;
  startDate.setDate(startDate.getDate() - mondayOffset);
  
  // 循环生成每一周的组件
  while (startDate.getTime() <= lastDayOfMonth.getTime()) {
    const weekStart = new Date(startDate);
    const weekEnd = new Date(startDate);
    weekEnd.setDate(weekEnd.getDate() + 6); // 周一加6天即为当周周日
    // 用周起始时间戳作为唯一key,避免组件复用错误
    ans.push(<SingleWeek key={weekStart.getTime()} startDate={weekStart} endDate={weekEnd} />);
    // 偏移到下一周
    startDate.setDate(startDate.getDate() + 7);
  }
  return ans;
}

周组件修复

function SingleWeek(props) {
  const { startDate } = props;
  const week = [];
  // 用let声明块级作用域变量,避免var的变量提升问题
  for (let i = 0; i < 7; i++) {
    const curDate = new Date(startDate);
    curDate.setDate(curDate.getDate() + i);
    // 单日组件用当天时间戳作为唯一key
    week.push(<SingleDay key={curDate.getTime()} currentDate={curDate} />);
  }
  return (
    <div style={{display: "flex"}}>
      {week}
    </div>
  );
}

注:原SingleWeek组件中并未使用endDate参数,可根据实际业务需求决定是否保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:39:33