ReactDOM v18下FullCalendar使用dayCellDidMount自定义日期的Bug修复咨询
问题描述
将react-dom升级到v18版本后,原本实现的每月第一天显示格式(如“01 oct.”)出现了原有格式与自定义格式混合的问题。
相关代码如下:
const customDayLabel = (date: Date, view: CalendarView): void => { if (view === CalendarView.Month) { const currentDate = new Date(date).setDate(DAY_ONE) const dates = [addMonths(currentDate, ONE_MONTH), currentDate] for (const targetDate of dates) { const dataDate = format(targetDate, 'yyyy-MM-dd') const element = document.querySelector( `.fc-daygrid-day[data-date="${dataDate}"] a` ) if (element) { const dateLabel = format(targetDate, 'dd MMM.') element.innerHTML = dateLabel } } } }
const Calendar = ({ setCalendarRef, view, date, ...otherProps }: CalendarProps) => { const headerView = view || otherProps.initialView || CalendarView.Month const dayRender = useCallback(() => { customDayLabel(date, headerView) }, [date, headerView]) return ( <FullCalendar ref={setCalendarRef} editable droppable navLinks allDayText='' locale='pt-BR' // for 0-23 hour format forceEventDuration moreLinkText='mais' headerToolbar={false} fixedWeekCount={false} plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]} slotLabelFormat={slotLabelFormat} dayPopoverFormat={dayPopoverFormat} dayHeaderContent={customHeader} dayCellDidMount={dayRender} initialDate={date} {...otherProps} /> ) }
已尝试将dayCellDidMount替换为dayCellContent,但该方法仅能渲染修改后的标签,无法解决格式混合问题。

修复方案
核心原因
react-dom v18启用了自动批处理和并发渲染机制,FullCalendar在该环境下的DOM更新时机与dayCellDidMount的执行时机不再同步。你之前直接操作DOM修改innerHTML的方式,会被FullCalendar后续的内部渲染逻辑覆盖,导致原有格式与自定义格式混合。
方法1:使用dayCellContent自定义渲染(推荐)
之前误用了dayCellContent,这个回调的正确用法是返回自定义内容,由FullCalendar负责渲染,完全避免DOM操作冲突。
修改步骤:
- 替换原有的
customDayLabel和dayRender逻辑,实现dayCellContent回调:
import { DayCellContentArg } from '@fullcalendar/react'; const customDayCellContent = (info: DayCellContentArg) => { // 判断当前日期是否为每月第一天 const isFirstDay = info.date.getDate() === 1; if (isFirstDay) { // 返回自定义格式的日期文本 return format(info.date, 'dd MMM.'); } // 非第一天返回默认的日期数字文本 return info.dayNumberText; };
- 更新FullCalendar组件的属性,移除
dayCellDidMount,添加dayCellContent:
<FullCalendar ref={setCalendarRef} editable droppable navLinks allDayText='' locale='pt-BR' forceEventDuration moreLinkText='mais' headerToolbar={false} fixedWeekCount={false} plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]} slotLabelFormat={slotLabelFormat} dayPopoverFormat={dayPopoverFormat} dayHeaderContent={customHeader} dayCellContent={customDayCellContent} // 替换为这个属性 initialDate={date} {...otherProps} />
这种方式完全遵循FullCalendar的渲染逻辑,不会和React 18的并发渲染机制冲突,从根源解决格式混合问题。
方法2:调整DOM操作的执行时机(备选)
如果因特殊需求必须保留直接操作DOM的方式,需要确保修改DOM的代码在FullCalendar完成渲染后执行:
const dayRender = useCallback(() => { // 通过setTimeout延迟执行,确保FullCalendar的DOM更新完成 setTimeout(() => { customDayLabel(date, headerView); }, 0); }, [date, headerView]);
但这种方式依赖渲染时机,在React 18的并发模式下仍可能出现不稳定情况,仅作为临时替代方案。
内容的提问来源于stack exchange,提问作者Karine Brandelli Padilha
相关产品推荐
相关产品推荐

