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

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操作冲突。

修改步骤:

  1. 替换原有的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;
};
  1. 更新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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:02:53