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

Fullcalendar React:同一查询同时更新事件与资源的方案咨询

解决FullCalendar React中事件与资源联动更新的问题

我之前也遇到过类似的困扰——用datesRender确实很容易触发渲染循环,因为它会在日历的每一次渲染(包括事件/资源更新后)都触发,进而导致状态更新→渲染→状态更新的死循环。这里给你一套经过验证的解决方案,核心思路是用状态统一管理数据,通过datesSet事件监听日期范围变化,配合useMemo缓存资源计算结果:

核心步骤

1. 用React状态存储事件数据

首先,我们不再使用FullCalendar的events/resources函数式回调,而是用React的useState来存储处理好的事件数据,资源则基于事件数据动态计算:

import { useState, useMemo } from 'react';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import resourceTimelinePlugin from '@fullcalendar/resource-timeline';

const MyCalendar = () => {
  // 存储可视范围内的事件数据
  const [visibleEvents, setVisibleEvents] = useState([]);
  // 可选:添加loading状态防止重复请求
  const [isLoading, setIsLoading] = useState(false);

2. 用useMemo从事件中生成资源列表

利用useMemo缓存资源计算结果,只有当事件数据变化时才重新生成资源列表,避免不必要的重计算:

// 从可视事件中提取唯一资源
  const resources = useMemo(() => {
    if (!visibleEvents.length) return [];
    
    // 用Map去重,确保每个资源只出现一次
    const resourceMap = new Map();
    visibleEvents.forEach(event => {
      // 假设你的事件中包含resourceId和resourceName字段
      if (!resourceMap.has(event.resourceId)) {
        resourceMap.set(event.resourceId, {
          id: event.resourceId,
          title: event.resourceName
        });
      }
    });
    
    return Array.from(resourceMap.values());
  }, [visibleEvents]);

3. 用datesSet事件监听日期范围变化

datesSet只会在日历的可视日期范围真正改变时触发(比如切换月份、周,或者调整视图),不会因为事件/资源更新而触发,完美避免了渲染循环:

// 处理日期范围变化,获取对应事件
  const handleDatesSet = async (info) => {
    if (isLoading) return; // 防止重复请求
    setIsLoading(true);
    
    try {
      // 调用你的API,传入当前可视的start和end日期
      const rawEvents = await fetchEvents(info.start.toISOString(), info.end.toISOString());
      // 更新事件状态,资源会自动通过useMemo生成
      setVisibleEvents(rawEvents);
    } catch (err) {
      console.error('获取事件失败:', err);
    } finally {
      setIsLoading(false);
    }
  };

4. 配置FullCalendar组件

最后把状态和回调传给FullCalendar即可:

return (
    <FullCalendar
      plugins={[dayGridPlugin, resourceTimelinePlugin]}
      initialView="resourceTimelineDay"
      // 绑定datesSet事件
      datesSet={handleDatesSet}
      // 直接传递状态中的事件和计算好的资源
      events={visibleEvents}
      resources={resources}
      // 其他你的日历配置...
    />
  );
};

export default MyCalendar;

关键注意事项

  • 为什么不用datesRender?
    datesRender会在日历的每一次渲染周期触发,包括当你更新events/resources状态后,这会导致状态更新→渲染→datesRender→状态更新的循环,而datesSet只在日期范围实际变化时触发,从根源上避免了循环。
  • 关于API请求:
    如果你的业务中同一日期范围的请求可能重复触发,一定要加isLoading状态拦截,或者对请求参数做缓存,避免不必要的网络请求。
  • 资源字段自定义:
    上面的示例假设事件中包含resourceId和resourceName,你可以根据自己的业务结构调整资源的生成逻辑,比如从事件的其他字段提取资源信息。

内容的提问来源于stack exchange,提问作者Victor.dMdB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:39:41