如何在映射的JSX元素中隔离函数以避免无限重渲染?
解决日历组件无限重渲染问题
问题根源
导致无限重渲染的核心原因:
- 在
setDayCellVariant中调用setVariant(通过handleHookCall),每次调用都会触发组件state更新,引发重渲染 - 重渲染时会再次调用
setDayCellVariant,再次触发state更新,形成循环 - 全局
variantstate设计错误,每个日期单元格的样式变体应独立判断,无需统一维护state
解决方案
1. 移除全局variant相关代码
删掉全局的variant state和handleHookCall函数,因为不需要统一维护变体状态:
// 移除以下代码 // const [variant, setVariant] = useState('default') // const handleHookCall = () => { // setVariant('reserved') // }
2. 预处理预订日期为Set(提升性能)
用useMemo将预订数据中的日期转换成Set,把日期判断的时间复杂度从O(n)降到O(1),同时避免每次渲染重复处理数据:
const reservedDates = useMemo(() => { if (!supabaseloaded || !reservationsData) return new Set(); return new Set(reservationsData.map(item => item.in_between_dates)); }, [supabaseloaded, reservationsData]);
3. 重写setDayCellVariant为纯函数
修改为纯函数,仅根据传入日期判断是否在预订Set中,返回对应变体值,并用useCallback缓存:
const setDayCellVariant = useCallback((day) => { const formattedDay = dayjs(day).format('YYYY-MM-DD'); return reservedDates.has(formattedDay) ? 'reserved' : 'default'; }, [reservedDates]);
4. 保留原JSX调用方式
原JSX中的调用逻辑无需修改,现在函数是纯函数,不会触发state更新:
<Styles.CalendarDayCell key={`day-${dayIndex}`} onClick={() => handleClick(day)} onDoubleClick={() => handleDoubleClick(day)} variant={setDayCellVariant(day)} > {day.getDate()} <HalfDay /> <div></div> <div></div> </Styles.CalendarDayCell>
额外优化
用useMemo缓存generateWeeksOfTheMonth,避免每次渲染重新生成日期数组,减少不必要重渲染:
const generateWeeksOfTheMonth = useMemo(() => { // 你的月份周数生成逻辑 }, [selectedDate, firstDayOfFirstWeekOfMonth]);
修改后,组件只会在预订数据变化、选中日期变化时重新计算相关内容,彻底解决无限重渲染问题,同时提升性能。
内容的提问来源于stack exchange,提问作者lacadaemon94
相关产品推荐
相关产品推荐

