基于react-beautiful-dnd实现类别拖拽及跨类别拖拽项更新
解决方案
一、实现类别拖拽排序
要让静态类别支持拖拽排序,需完成以下操作:
- 将
categories转为React状态
把原来的静态类别数组改为状态变量,方便拖拽后更新排序:
const [categories, setCategories] = useState([ // 替换为你的初始类别数据,示例:{ id: 1, name: "待办" }, { id: 2, name: "已完成" } ]);
- 重构DragDropContext结构
在外层新增顶级Droppable容器承载所有可拖拽类别,每个类别用Draggable包裹,同时保留类别内部存放items的Droppable:
<DragDropContext onDragEnd={handleDragEnd}> {/* 顶级类别容器,支持垂直拖拽排序 */} <Droppable droppableId="category-list" direction="vertical"> {(categoryContainerProvided) => ( <div ref={categoryContainerProvided.innerRef} {...categoryContainerProvided.droppableProps} > {categories.map((category, idx) => ( {/* 每个类别作为可拖拽项 */} <Draggable key={category.id} draggableId={category.id.toString()} index={idx} type="category" // 标记拖拽类型,区分item拖拽 > {(categoryProvided) => ( <div ref={categoryProvided.innerRef} {...categoryProvided.draggableProps} {...categoryProvided.dragHandleProps} style={{ margin: "10px 0", padding: "10px", border: "1px solid #eee" }} // 可选:添加样式方便拖拽识别 > {/* 原有类别内部的item容器 */} <Droppable droppableId={category.id.toString()}> {(itemContainerProvided) => ( <div ref={itemContainerProvided.innerRef} {...itemContainerProvided.droppableProps} > <Category category={category} items={items} provided={itemContainerProvided} /> {itemContainerProvided.placeholder} </div> )} </Droppable> </div> )} </Draggable> ))} {categoryContainerProvided.placeholder} </div> )} </Droppable> </DragDropContext>
- 更新拖拽结束逻辑,处理类别排序
在handleDragEnd中先判断拖拽类型,单独处理类别排序:
const handleDragEnd = (result) => { const { source, destination, type } = result; // 无有效目标时直接返回 if (!destination) return; // 处理类别拖拽排序 if (type === "category") { // 拖拽位置未变化时无需更新 if (source.index === destination.index) return; const updatedCategories = [...categories]; const [movedCategory] = updatedCategories.splice(source.index, 1); updatedCategories.splice(destination.index, 0, movedCategory); setCategories(updatedCategories); return; } // 原有item拖拽逻辑保持不变 if (destination.droppableId !== source.droppableId) { setItems(prevItems => prevItems.map(item => item.id === parseInt(result.draggableId) ? { ...item, category: parseInt(destination.droppableId) } : item ) ); } else { const itemsCopy = [...items]; const [removed] = itemsCopy.splice(source.index, 1); itemsCopy.splice(destination.index, 0, removed); setItems(itemsCopy); } };
二、确保跨类别拖拽时同步更新item.category
你当前的代码已实现该功能,可优化代码可读性并确保使用prevState避免状态更新竞态:
// 跨类别拖拽时的逻辑片段 if (destination.droppableId !== source.droppableId) { setItems(prevItems => prevItems.map(item => { if (item.id === parseInt(result.draggableId)) { return { ...item, category: parseInt(destination.droppableId) }; } return item; }) ); }
这段代码基于上一次的items状态更新,保证数据与UI一致。
内容的提问来源于stack exchange,提问作者SVE
相关产品推荐
相关产品推荐

