自定义预约日历性能优化求助:1008个组件渲染卡顿问题
优化28天预约日历渲染卡顿的方案
1. 阻止无意义的组件重渲染
- 给日程方块组件套上
React.memo(),让它只在props(比如选中状态、日程数据)真的变化时才重新渲染。如果props是对象、数组这类引用类型,要用useMemo缓存数据,useCallback缓存事件回调,保证每次传递的引用稳定。const ScheduleBlock = React.memo(({ data, isSelected, onSelect }) => { // 方块组件逻辑 }); // 父组件里缓存数据与回调 const cachedBlockData = useMemo(() => generate28DaysBlocks(), []); const handleBlockSelect = useCallback((blockId) => { setSelectedBlock(blockId); }, []); - 拆分状态:别把全局选中状态放在顶层父组件,要么把选中状态下沉到方块组件内部,要么用局部状态管理逻辑,只让被点击的方块更新自身状态,避免触发所有1008个组件重渲染。
2. 虚拟滚动(核心优化手段)
用户视野内只能看到部分方块,没必要一次性渲染全部1008个。用虚拟滚动只渲染当前可见区域的组件,其余区域用空白占位模拟高度:
- 先给日历容器设置固定高度并开启滚动,计算每个方块的宽高以及容器的可视高度。
- 监听容器滚动事件,算出当前可见的起始行和结束行:比如
startRow = Math.floor(scrollTop / blockHeight),endRow = startRow + 可视范围内行数。 - 只渲染对应行的方块(比如一次渲染5行×36列=180个组件),同时在容器顶部和底部添加空白div占位,保持总高度和完整日历一致。
3. 事件委托替代单个绑定
不给每个方块单独绑onClick,把点击事件绑在日历容器上,通过事件冒泡获取点击的方块元素,再处理选中逻辑。减少事件绑定数量,也避免组件更新时重复绑定事件:
const CalendarContainer = () => { const handleContainerClick = (e) => { const blockEl = e.target.closest('.schedule-block'); if (blockEl) { const blockId = blockEl.dataset.blockId; setSelectedBlock(blockId); } }; return ( <div className="calendar-container" onClick={handleContainerClick}> {/* 渲染可见范围内的方块 */} </div> ); };
4. 批量处理状态更新
如果选中操作会触发多个状态变更,用useReducer或者React的批量更新机制(React 18默认自动批量更新,手动场景可使用unstable_batchedUpdates),减少整体渲染次数。
5. 简化方块组件结构
检查日程方块内部是否有冗余的子组件或复杂逻辑,尽量精简DOM结构。比如把静态文本、通用样式这类内容提取到父组件,避免每个方块重复渲染相同的静态元素。
内容的提问来源于stack exchange,提问作者Zeeshan karim
相关产品推荐
相关产品推荐

