React FullCalendar中如何将选中月份日期范围存入state并避免无限重渲染
解决FullCalendar datesSet触发无限重渲染问题
你遇到的问题核心是:每次datesSet触发时直接调用setDateRange(arg)会导致组件重渲染,而FullCalendar重新渲染后又会再次触发datesSet,形成无限循环。
修复步骤:
- 用
useRef存储上一次的日期范围,对比当前范围是否真正变化,仅在变化时更新state - 避免直接存储
datesSet返回的完整arg对象(因为每次触发的arg可能是新对象,即使日期范围没变,也会触发state更新)
修改后的代码示例:
import { useState, useRef } from 'react'; // ...其他导入 const YourComponent = () => { const [dateRange, setDateRange] = useState<{ start: Date; end: Date }>(); const prevDateRangeRef = useRef<{ start: Date; end: Date }>(); const handleDatesSet = (arg: any) => { // 提取关键的日期范围字段 const newRange = { start: arg.start, end: arg.end }; // 对比是否和上一次的范围一致,避免不必要的state更新 if (!prevDateRangeRef.current || prevDateRangeRef.current.start.getTime() !== newRange.start.getTime() || prevDateRangeRef.current.end.getTime() !== newRange.end.getTime()) { setDateRange(newRange); prevDateRangeRef.current = newRange; } }; return ( <Box flex="1 1 100%" ml="15px" sx={{backgroundColor: 'white', borderRadius:3, boxShadow: '0px 2px 4px 1px rgba(0,0,0,0.25)', p:3, marginBottom:2, width:'100%'}}> <FullCalendar height="75vh" locales={[enLocale, frLocale]} locale={frLocale} weekNumberCalculation="ISO" plugins={[ dayGridPlugin, timeGridPlugin, interactionPlugin, listPlugin, ]} headerToolbar={{ left: "prev,next today", center: "title", right: rightElement, }} initialView="dayGridMonth" // 修复原代码的单引号语法错误 editable={true} selectable={true} selectMirror={true} datesSet={handleDatesSet} dayMaxEvents={true} select={handleDateClick} eventChange={handleEventChange} eventClick={handleEventClick} eventsSet={(events:any) => setCurrentEvents(events)} initialEvents={newArray} /> </Box> ); };
关键说明:
- 用useRef跟踪上一次范围:通过对比时间戳(
getTime())判断日期是否真正变化,避免因对象引用变化导致的无意义更新 - 只存储必要字段:不再存储完整的
arg对象,只保留start和end日期,减少state更新的触发频率 - 修复语法错误:原代码中
initialView={dayGridMonth'}存在单引号位置错误,已修正为initialView="dayGridMonth"
这样修改后,只有当用户切换月份或视图导致日期范围真正变化时,才会更新dateRange state,彻底解决无限重渲染问题。
内容的提问来源于stack exchange,提问作者Edouard WILLEMS
相关产品推荐
相关产品推荐

