使用FullCalendar React的eventContent导致事件重复渲染问题求助
问题
我在使用FullCalendar React自定义周历视图的事件显示时遇到了性能问题:
- 只要设置了
eventContent(哪怕只是返回事件标题的基础实现),切换上一周/下一周时所有事件都会重新渲染;但不设置eventContent时,事件仅渲染一次。 - 我的日历需要加载数千条股票市场企业财报事件,事件通过回调函数结合
fetchEvents按当前视图起止日期从JSON文件获取。 - 希望实现包含企业名称(存在
event.extendedProps)、开始时间、股票代码(设为event标题)的自定义事件视图,同时避免重复渲染提升性能。
代码示例:
const eventContent = (eventInfo) => { const {event} = eventInfo; return (<span>{event.title}</span>) }
<FullCalendar plugins={[dayGridPlugin]} initialView="dayGridWeek" weekends={true} events={events} eventDisplay="block" eventOrder="start, title" timeZone="local" eventContent={eventContent} headerToolbar={{ start: "prev", center: "title", end: "next", }} allDaySlot={false} />
解决方案
1. 用React.memo缓存自定义事件组件
FullCalendar每次切换视图时会重新调用eventContent生成新的React元素,哪怕事件数据没变化。用React.memo包裹自定义事件组件,只有当传入的事件数据发生变化时才会重新渲染。
修改代码:
// 定义纯组件并缓存 const EventContent = React.memo(({ event }) => { return ( <span> {event.title} - {event.extendedProps.companyName} </span> ); }); // 传入eventContent const eventContent = (eventInfo) => { return <EventContent event={eventInfo.event} />; };
2. 稳定事件数据的引用
确保events回调返回的事件对象引用稳定——每次获取数据后,用唯一标识(比如股票代码)复用对象引用,避免因对象重新创建触发不必要的渲染。可以结合useMemo和useCallback缓存事件数据和获取函数:
const fetchEvents = useCallback((info, successCallback) => { fetch(`/your-data-url?start=${info.startStr}&end=${info.endStr}`) .then(res => res.json()) .then(data => { const processedEvents = data.map(item => ({ id: item.stockCode, // 用唯一ID确保引用稳定 title: item.stockCode, start: item.reportDate, extendedProps: { companyName: item.companyName } })); successCallback(processedEvents); }); }, []); // 缓存events配置,避免每次渲染生成新函数 const events = useMemo(() => fetchEvents, [fetchEvents]);
3. 用原生DOM操作替代React组件渲染
如果自定义内容逻辑简单,可以绕过React的渲染机制,通过eventDidMount钩子在事件首次挂载时手动插入DOM内容,只有事件被销毁重建时才会重新执行,减少重复计算:
const eventDidMount = (info) => { const eventEl = info.el; eventEl.innerHTML = ''; const contentEl = document.createElement('span'); contentEl.textContent = `${info.event.title} - ${info.event.extendedProps.companyName}`; eventEl.appendChild(contentEl); }; // 修改FullCalendar配置,移除eventContent,添加eventDidMount <FullCalendar plugins={[dayGridPlugin]} initialView="dayGridWeek" weekends={true} events={events} eventDisplay="block" eventOrder="start, title" timeZone="local" headerToolbar={{ start: "prev", center: "title", end: "next", }} allDaySlot={false} eventDidMount={eventDidMount} />
内容的提问来源于stack exchange,提问作者koka
相关产品推荐
相关产品推荐

