React Beautiful Drag and Drop拖拽失效,请求排查代码问题
问题排查:react-beautiful-dnd 拖拽异常
问题描述
使用 react-beautiful-dnd 编写拖拽列表时,拖拽列表项出现元素位置错乱、重复显示的异常(拖拽元素时原位置元素未消失,拖拽元素出现偏移),代码及问题如下:
原代码
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; const Column = () => { const itemList = [ { id: "1", task: "Pierwszy element" }, { id: "2", task: "Drugi element" }, { id: "3", task: "Trzeci element" }, { id: "4", task: "Czwarty element" }, { id: "5", task: "Piąty element" }, { id: "6", task: "Szósty element" }, ]; return ( <DragDropContext> <div className="border-4 border-base-300 bg-base-300 mx-auto mt-2 w-[500px] rounded-md font-sans"> <h1 className="text-center p-1 text-lg font-bold"> Drag and drop list </h1> <Droppable droppableId="characters"> {(provided) => ( <ul className="bg-base-300 characters" {...provided.droppableProps} ref={provided.innerRef} > {itemList.map((item, index) => { return ( <Draggable key={item.id} draggableId={item.id} index={index}> {(provided) => ( <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} className="font-sans p-3 text-[15px] my-2 last:my-0 bg-base-200" > {item.task} </li> )} </Draggable> ); })} {provided.placeholder} </ul> )} </Droppable> </div> </DragDropContext> ); }; export default Column;
错误原因及修复方案
1. 缺少 DragDropContext 的 onDragEnd 回调
react-beautiful-dnd 强制要求为 DragDropContext 提供 onDragEnd 函数,这是库处理拖拽结束后状态重置、位置修正的核心入口。没有该回调,库无法正确处理拖拽后的视图逻辑,直接导致视觉错乱。
2. 列表数据未做响应式管理
原代码中 itemList 是静态常量,拖拽排序后无法触发组件重新渲染,视图不会更新。需要用 useState 将其转为响应式状态,确保排序后列表能实时刷新。
修复后的代码
import { useState } from "react"; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; const Column = () => { // 用 useState 管理列表数据,实现响应式更新 const [itemList, setItemList] = useState([ { id: "1", task: "Pierwszy element" }, { id: "2", task: "Drugi element" }, { id: "3", task: "Trzeci element" }, { id: "4", task: "Czwarty element" }, { id: "5", task: "Piąty element" }, { id: "6", task: "Szósty element" }, ]); // 处理拖拽结束逻辑,完成列表排序 const handleDragEnd = (result) => { // 若拖拽未完成(如拖到容器外),直接终止 if (!result.destination) return; const items = Array.from(itemList); // 移除原位置元素 const [reorderedItem] = items.splice(result.source.index, 1); // 将元素插入目标位置 items.splice(result.destination.index, 0, reorderedItem); setItemList(items); }; return ( // 添加上必填的 onDragEnd 回调 <DragDropContext onDragEnd={handleDragEnd}> <div className="border-4 border-base-300 bg-base-300 mx-auto mt-2 w-[500px] rounded-md font-sans"> <h1 className="text-center p-1 text-lg font-bold"> Drag and drop list </h1> <Droppable droppableId="characters"> {(provided) => ( <ul className="bg-base-300 characters" {...provided.droppableProps} ref={provided.innerRef} > {itemList.map((item, index) => { return ( <Draggable key={item.id} draggableId={item.id} index={index}> {(provided) => ( <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} className="font-sans p-3 text-[15px] my-2 last:my-0 bg-base-200" > {item.task} </li> )} </Draggable> ); })} {provided.placeholder} </ul> )} </Droppable> </div> </DragDropContext> ); }; export default Column;
额外说明
handleDragEnd中的数组操作是 react-beautiful-dnd 的标准排序流程,通过复制原数组、剪切粘贴元素的方式避免直接修改原状态。- 确保
draggableId和组件key使用唯一稳定的标识(此处用item.id是正确的),不要用index作为 key,否则排序后可能出现组件复用异常。
内容的提问来源于stack exchange,提问作者MISIU
相关产品推荐
相关产品推荐

