React组件重渲染时如何防止日期变量被意外更新
问题根源
你的日期意外递增是两个代码逻辑问题共同导致的:
addHours函数直接修改传入的Date引用类型对象:date.setTime会直接改动原对象存储的时间值,而你传入的helperDate.current是跨渲染持久存储的ref值,每次渲染执行map循环时,都会从i=1到i=6连续6次给这个ref里存的原始日期加24小时,相当于每次组件重渲染,起始日期就被往后推了6天。- 渲染日期数字时直接读取
helperDate.current,没有使用当前列对应偏移后的日期值,哪怕修复了累加问题,所有列也会显示同一个日期。
修复方法
- 把日期计算改成纯函数逻辑:永远不修改传入的原始日期对象,每次计算偏移都基于原始时间戳生成新的
Date实例返回,从根源避免污染ref存储的初始值。 - 渲染每一列时,单独生成当前列对应的日期副本,用这个副本取星期和日期值,不要共用可变的ref日期对象。
- 固定常量
dayList可以提到组件作用域外,避免每次渲染重复创建。
修正后的代码
首先调整常量定义和辅助函数:
// 提到组件外的固定常量 const dayList = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", ]; // 纯函数版日期偏移计算,不修改传入的原日期 const addHours = (hours, baseDate, offsetCount) => { const offsetTime = hours * offsetCount * 60 * 60 * 1000; return new Date(baseDate.getTime() + offsetTime); };
然后修改表头渲染逻辑:
<div className="rabColumnTitlesWrapper"> {Array(7) .fill(0) .map((_, i) => { // 为当前列生成独立的日期副本,不改动ref存储的初始值 const currentColDate = addHours(24, helperDate.current, i); return ( <div className="rabColumnTitle" key={i}> {dayList[getDay(currentColDate)] .substring(0, 3) .toUpperCase()} <br /> <span>{getDate(currentColDate)}</span> </div> ); })} </div>
额外注意
如果你后续需要实现上一周/下一周切换功能,更新startDate状态时记得同步更新helperDate.current的值,否则切换周后表头日期不会同步刷新:
const handleWeekChange = (weekOffset) => { const newStartDate = addWeeks(startDate, weekOffset); setStartDate(newStartDate); setEndDate(endOfWeek(newStartDate)); helperDate.current = newStartDate; // 同步更新ref存储的周起始日期 };
内容的提问来源于stack exchange,提问作者U. Watt
相关产品推荐
相关产品推荐

