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
相关产品推荐
相关产品推荐

