I have a list of columns where each column has list of tasks. When I drag the task first time, it works properly but when I drag the task second time then the other tasks get squeezed over and it doesn't work properly. Could anyone guide me what I could be doing wrong?
react-beautiful-dnd version is 13.1.1
Here is my following code
import React, { useEffect, useState } from "react";
import List from "../common/List";
import "./styles.scss";
import { DragDropContext } from "react-beautiful-dnd";
import { Droppable } from "react-beautiful-dnd";
import { Draggable } from "react-beautiful-dnd";
const Landing = () => {
const [columns, setColumns] = useState([
{
id: "1",
name: "To Do",
tasks: [
{
name: "Hello world",
id: "10",
},
{
name: "Fundraiser",
id: "11",
},
{
name: "BuybackTek",
id: "12",
},
{
name: "Create an element",
id: "13",
},
],
},
]);
const onDragEnd = (event) => {
const { destination, source, draggableId } = event;
if (!destination) return;
if (
destination.droppableId === source.droppableId &&
destination.index === source.index
)
return;
if (destination.droppableId === source.droppableId) {
console.log(event);
let tempColumns = JSON.parse(JSON.stringify(columns))
// let columnIndex = tempColumns.map((item)=>item.id).indexOf(source.droppableId);
let columnTasks = [...tempColumns[0].tasks]
let [removed] = columnTasks.splice(source.index , 1)
console.log("Removed: " , removed);
columnTasks.splice(destination.index , 0 , removed)
tempColumns[0].tasks = [...columnTasks]
setColumns(tempColumns)
}
};
useEffect(()=>{
console.log("Columns: " , columns);
} , [columns])
return (
<div className="landing-container">
<DragDropContext onDragEnd={onDragEnd}>
<div className="landing-wrapper">
{columns.map((item, index) => (
<div className="column-wrapper" key={index}>
<div className="column-header">{item.name}</div>
<Droppable droppableId={`column-${item.id}`}>
{(provider) => (
<div
className="drop-section"
ref={provider.innerRef}
{...provider.droppableProps}
>
{item.tasks.map((task, index) => (
<Draggable
draggableId={`task-${task.id}`}
index={index}
key={index}
>
{(provider) => (
<div
className="list-wrapper"
ref={provider.innerRef}
{...provider.dragHandleProps}
{...provider.draggableProps}
>
<div className="list">
<div className="name">{task.name}</div>
</div>
</div>
)}
</Draggable>
))}
{provider.placeholder}
</div>
)}
</Droppable>
</div>
))}
</div>
</DragDropContext>
</div>
);
};
export default Landing;
You shouldn't use indexes as the keys for the Draggables. You can use draggableId
as their key instead since it should be unique as well.
<Draggable
draggableId={`task-${task.id}`}
index={index}
key={`task-${task.id}`}
>
As mentioned in the React doc for list item keys, keys of the items must not change. Hence, you shouldn't use index to generate keys if the order of items may change. The keys for each item will change (in each re-render) since indexes are based on the order of the items in the list.