在react-virtualized List中使用react-beautiful-dnd出现拖拽报错
解决react-virtualized List与react-beautiful-dnd拖拽时"Cannot find droppable entry with id"错误
问题根源
react-virtualized的List组件会动态卸载视口外的行(即你的Section对应的Droppable组件),而react-beautiful-dnd要求所有可能的目标Droppable必须始终存在于DOM中,才能在拖拽过程中追踪目标区域。当你拖拽元素到一个已被卸载的Section位置时,就会触发找不到droppable id的报错。
解决方案
方法1:拖拽时临时禁用虚拟列表的DOM卸载
通过状态控制,在拖拽过程中强制所有Section保持挂载,确保react-beautiful-dnd能定位到所有目标Droppable,拖拽结束后恢复虚拟列表的正常渲染:
- 添加拖拽状态管理:
import { useState } from 'react'; const [isDragging, setIsDragging] = useState(false); const onDragStart = () => { setIsDragging(true); }; const onDragEnd = (result) => { setIsDragging(false); // 原有拖拽结束逻辑(如更新sections数组) };
- 修改List组件配置:
<List autoHeight={!isDragging} // 拖拽时设置足够大的高度,让所有Section都显示(可根据实际Section高度调整数值) height={isDragging ? state.sections.length * 200 : height} width={width} rowCount={state.sections.length} rowHeight={cache.rowHeight} deferredMeasurementCache={cache} rowRenderer={rowRenderer} scrollTop={scrollTop} // 拖拽时预渲染所有行,避免视口外Section被卸载 overscanRowCount={isDragging ? state.sections.length : 10} />
- 更新DragDropContext的回调:
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
方法2:将Droppable提升至虚拟列表外层,自定义分组拖拽逻辑
放弃每个Section作为独立Droppable,改为整个List作为单一Droppable,通过坐标计算判断拖拽目标Section,彻底规避虚拟列表DOM卸载的冲突:
- 调整组件结构:
<DragDropContext onDragEnd={onDragEnd}> <WindowScroller> {({ height, scrollTop }) => ( <AutoSizer disableHeight> {({ width }) => ( <Droppable droppableId="all-sections"> {(provided) => ( <div ref={provided.innerRef} {...provided.droppableProps}> <List autoHeight height={height} width={width} rowCount={state.sections.length} rowHeight={cache.rowHeight} deferredMeasurementCache={cache} rowRenderer={rowRenderer} scrollTop={scrollTop} /> {provided.placeholder} </div> )} </Droppable> )} </AutoSizer> )} </WindowScroller> </DragDropContext>
- 自定义拖拽目标判断逻辑:
在onDragEnd中,通过拖拽结束的坐标,结合每个Section的位置信息,计算出目标Section,再更新sections数组完成元素迁移。这种方式需要额外处理DOM坐标获取,但能完美兼容虚拟列表的动态渲染特性。
方法3:使用第三方兼容库
使用react-beautiful-dnd-virtualized这类专门解决两者兼容问题的库,它会自动处理拖拽过程中虚拟列表的行渲染策略,确保目标Droppable始终存在于DOM中,无需手动修改虚拟列表配置。
内容的提问来源于stack exchange,提问作者Volodymyr Trykoz
相关产品推荐
相关产品推荐

