Search code examples
reactjsreact-beautiful-dnd

When I drag an item second time, the lists other than the dragged itemget squeezed over using react-beautiful-dnd


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

enter image description here

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;

Solution

  • 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.