React Beautiful DND组件无法拖拽问题求助
React Beautiful DND 拖拽功能失效排查与修复
问题描述
使用React Beautiful DND实现看板拖拽功能,代码无报错但组件完全无法拖拽,需要排查原因并修复。
完整代码
导入部分
import React, { useState } from "react"; import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
数据与函数定义
const tasks = [ { id: "1", content: "First task" }, { id: "2", content: "Second task" }, { id: "3", content: "Third task" }, { id: "4", content: "Fourth task" }, { id: "5", content: "Fifth task" } ]; const taskStatus = { requested: { name: "Requested", items: tasks }, toDo: { name: "To do", items: [] }, inProgress: { name: "In Progress", items: [] }, done: { name: "Done", items: [] } }; const onDragEnd = (result, columns, setColumns) => { if (!result.destination) return; const { source, destination } = result; if (source.droppableId !== destination.droppableId) { const sourceColumn = columns[source.droppableId]; const destColumn = columns[destination.droppableId]; const sourceItems = [...sourceColumn.items]; const destItems = [...destColumn.items]; const [removed] = sourceItems.splice(source.index, 1); destItems.splice(destination.index, 0, removed); setColumns({ ...columns, [source.droppableId]: { ...sourceColumn, items: sourceItems }, [destination.droppableId]: { ...destColumn, items: destItems } }); } else { const column = columns[source.droppableId]; const copiedItems = [...column.items]; const [removed] = copiedItems.splice(source.index, 1); copiedItems.splice(destination.index, 0, removed); setColumns({ ...columns, [source.droppableId]: { ...column, items: copiedItems } }); } };
组件渲染部分
function App() { const [columns, setColumns] = useState(taskStatus); return ( <div> <h1 style={{ textAlign: "center" }}>Jira Board</h1> <div style={{ display: "flex", justifyContent: "center", height: "100%" }} > <DragDropContext onDragEnd={(result) => onDragEnd(result, columns, setColumns)} > {Object.entries(columns).map(([columnId, column], index) => { return ( <div style={{ display: "flex", flexDirection: "column", alignItems: "center" }} key={columnId} > <h2>{column.name}</h2> <div style={{ margin: 8 }}> <Droppable droppableId={columnId} key={columnId}> {(provided, snapshot) => { return ( <div {...provided.droppableProps} ref={provided.innerRef} style={{ background: snapshot.isDraggingOver ? "lightblue" : "lightgrey", padding: 4, width: 250, minHeight: 500 }} > {column.items.map((item, index) => { return ( <Draggable key={item.id} draggableId={item.id} index={index} > {(provided, snapshot) => { return ( <div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} style={{ userSelect: "none", padding: 16, margin: "0 0 8px 0", minHeight: "50px", backgroundColor: snapshot.isDragging ? "#263B4A" : "#456C86", color: "white", ...provided.draggableProps.style }} > {item.content} </div> ); }} </Draggable> ); })} {provided.placeholder} </div> ); }} </Droppable> </div> </div> ); })} </DragDropContext> </div> </div> ); } export default App;
问题排查与修复方案
你的代码存在两个核心问题导致拖拽失效:
状态初始化的引用共享问题
taskStatus.requested.items直接引用了tasks数组,useState(taskStatus)会保留这个原始引用,后续状态更新时可能因引用未变更导致组件不触发重新渲染。需要在初始化时创建数组副本:const [columns, setColumns] = useState(() => ({ ...taskStatus, requested: { ...taskStatus.requested, items: [...tasks] } }));onDragEnd中的状态快照过时问题
当前onDragEnd直接使用传入的columns参数,这是组件渲染时的旧状态快照,会导致状态更新逻辑基于过时数据执行。改用函数式更新可确保获取最新状态:const onDragEnd = (result) => { if (!result.destination) return; const { source, destination } = result; setColumns(prevColumns => { if (source.droppableId !== destination.droppableId) { const sourceColumn = prevColumns[source.droppableId]; const destColumn = prevColumns[destination.droppableId]; const sourceItems = [...sourceColumn.items]; const destItems = [...destColumn.items]; const [removed] = sourceItems.splice(source.index, 1); destItems.splice(destination.index, 0, removed); return { ...prevColumns, [source.droppableId]: { ...sourceColumn, items: sourceItems }, [destination.droppableId]: { ...destColumn, items: destItems } }; } else { const column = prevColumns[source.droppableId]; const copiedItems = [...column.items]; const [removed] = copiedItems.splice(source.index, 1); copiedItems.splice(destination.index, 0, removed); return { ...prevColumns, [source.droppableId]: { ...column, items: copiedItems } }; } }); };同时修改
DragDropContext的onDragEnd绑定:<DragDropContext onDragEnd={onDragEnd}>
修改以上两处后,拖拽功能即可正常工作。
内容的提问来源于stack exchange,提问作者Vins98
相关产品推荐
相关产品推荐

