import React, { useState } from "react";
import { useDrag, useDrop } from "react-dnd";
import "../Styles/DroppableComponent.css";

const DragDropItem = ({ item, onDrop, index }) => {
  const [{ isDragging }, drag] = useDrag({
    type: "DRAGGABLE_ITEM_TYPE",
    item: { id: item.id, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
    dragPreviewType: "none",
  });

  const itemStyles = {
    backgroundColor: "#f0f0f0",
    border: isDragging ? "5px dashed  #ccc" : "1px solid transparent",
    padding: "8px",
  };

  return (
    <div ref={drag} style={itemStyles} onClick={() => onDrop(item.id, index)}>
      <h3>{item.title}</h3>
      <ul>
        {item.names?.map((name, nameIndex) => (
          <li key={nameIndex}>{name}</li>
        ))}
      </ul>
    </div>
  );
};

const DroppableComponent = ({ data }) => {
  const [droppedItemIds, setDroppedItemIds] = useState([]);

  const handleDrop = (itemId, index) => {
    const item = data.find((item) => item.id === itemId);

    if (item) {
      const sameCategoryItems = droppedItemIds.filter(
        (id) => data.find((dataItem) => dataItem.id === id)?.category === item.category
      );

      const hoverIndex = index;
      const insertIndex = sameCategoryItems.findIndex((id) =>
        data.find((dataItem) => dataItem.id === id)?.category === item.category
          ? hoverIndex < sameCategoryItems.indexOf(id)
          : false
      );

      const newDroppedItemIds = [...droppedItemIds];
      newDroppedItemIds.splice(
        insertIndex === -1 ? sameCategoryItems.length : insertIndex,
        0,
        itemId
      );

      setDroppedItemIds(newDroppedItemIds);
    }
  };

  const [{ isOver, canDrop }, drop] = useDrop({
    accept: "DRAGGABLE_ITEM_TYPE",
    drop: (item) => {
      handleDrop(item.id, droppedItemIds.length);
    },
    collect: (monitor) => ({
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop(),
    }),
  });

  const gridStyles = {
    display: "grid",
    gridTemplateColumns: "repeat(2, 1fr)",
    gap: "8px",
    border: isOver && canDrop ? "2px dashed #ccc" : "2px dashed transparent",
    padding: "8px",
  };

  return (
    <div ref={drop} style={{ border: "2px dashed #ccc", padding: "16px" }}>
      <h2>Draggable and Droppable Container</h2>
      <div className="grid" style={gridStyles}>
        {droppedItemIds.map((itemId, index) => {
          const item = data.find((dataItem) => dataItem.id === itemId);
          return item ? (
            <DragDropItem key={itemId} item={item} onDrop={handleDrop} index={index} />
          ) : null;
        })}
      </div>
    </div>
  );
};
export default DroppableComponent;

I have draggable component and trying to drag and drop in droppable container which I am able to drop it. Meanwhile I am trying to implement drag and drop in the droppable component but while dragging and dropping its creating a copy. I need original items to be dragged and dropped or sorted within droppable component or container. how to achieve it.

1

There are 1 best solutions below

0
Dusan Jovanov On

The duplication is not an issue of react-dnd - it's how you handle the drop.

You need to remove the item from the state which holds items from where you're dragging and add it to the state which holds items where you're dropping.