0

I'm implementing a drag-and-drop feature using React Beautiful DND for managing files and folders from a cloud storage via a Node.js backend. Each item (file or folder) is represented by a separate React component. However, I'm encountering an issue where dragged items are moving automatically during the drag operation, and I'm also receiving an error: "invariant failed: draggable[id: vacation.jpg]: requires an integer index prop."

Here's a simplified version of my React components:


// main content component which render all the medias into the screen

const Content = () => {
  const navigate = useNavigate()
  const location = useLocation()

  const [isLoading, setIsLoading] = useState(true)

  const handleFolderClick = (path) => {
    navigate(`${location.pathname}/${path}`)
  }

  useEffect(() => {
    setTimeout(() => {
      setIsLoading(false)
    }, 1000)

    setIsLoading(true)
  }, [location.pathname])

  if (isLoading)
    return (
      <div className="spinner-border" role="status">
        <span className="visually-hidden">Loading...</span>
      </div>
    )

  return (
    <div className="container-fluid px-5 section-grid">
      <DragDropContext
        onDragEnd={(result) => {
          console.log(result.destination)
          if (!result.destination) return
        }}
      >
        {contents.children.map((item, index) => {
          if (item.type === 'folder') {
            return (
              <Folder
                key={index}
                name={item.name}
                index={index}
                onDirectoryNavigate={handleFolderClick}
              />
            )
          } else {
            return <File key={index} name={item.name} index={index} />
          }
        })}
      </DragDropContext>

      <Outlet />
    </div>
  )
}

export default Content

//  folder component

function Folder({ name, index, onDirectoryNavigate }) {
  return (
    <Droppable droppableId={name}>
      {(provided, snapshot) => (
        <div
          ref={provided.innerRef}
          {...provided.droppableProps}
          style={{ transform: snapshot.isDraggingOver && 'none' }}
        >
          <Draggable draggableId={name} index={index} key={index}>
            {(provided, snapshot) => (
              <div ref={provided.innerRef} {...provided.draggableProps}>
                <div
                  className="position-relative"
                  style={{
                    filter: 'drop-shadow(10px 10px 15px #11111143)',
                    userSelect: 'none',
                    transform: snapshot.isDragging ? 'scale(.7)' : 'scale(1)',
                    transition: 'all .2s ease-in-out',
                  }}
                  onDoubleClick={() => onDirectoryNavigate(name)}
                >
                  <div className="position-absolute w-100 h-100 p-5 d-flex align-items-center justify-content-center">
                    <button
                      style={{ all: 'unset', top: 7, left: 10, cursor: 'move' }}
                      className="position-absolute text-primary"
                      {...provided.dragHandleProps}
                    >
                      <FontAwesomeIcon icon={faUpDownLeftRight} />
                    </button>

                    <button
                      style={{ all: 'unset', top: 40, right: 10, fontSize: 22 }}
                      className="position-absolute text-primary"
                    >
                      <FontAwesomeIcon icon={faEllipsisVertical} />
                    </button>

                    <span className="fw-bold text-center text-primary">
                      {name}
                    </span>
                  </div>
                  <svg
                    className="w-100 h-100"
                    width="255"
                    height="179"
                    viewBox="0 0 255 179"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <path
                      d="M255 158.224C255 166.502 254.282 170.293 249.5 174.002C244.718 177.711 242 178.002 236 178.002H25.5C9.5 178.002 10.2822 177.711 5.5 174.002C0.717823 170.293 0 164.748 0 159.502V18.5022C0 13.2568 0.717823 7.21125 5.5 3.5022C10.2822 -0.206857 14 0.00214401 25.5 0.00214401H67L92.5 29.6688H229.5C236.263 29.6688 242.749 31.7525 247.531 35.4616C252.313 39.1706 255 44.2012 255 49.4466V158.224Z"
                      fill="white"
                    />
                  </svg>
                </div>
              </div>
            )}
          </Draggable>
          {provided.placeholder}
        </div>
      )}
    </Droppable>
  )
}

// file component

function File({ name, index }) {
  return (
    <Droppable droppableId={name}>
      {(provided, snapshot) => (
        <div ref={provided.innerRef} {...provided.droppableProps}>
          <Draggable draggableId={name} index={index} key={index}>
            {(provided, snapshot) => (
              <div ref={provided.innerRef} {...provided.draggableProps}>
                <div
                  className="position-relative"
                  style={{
                    filter: 'drop-shadow(10px 10px 15px #11111143)',
                    userSelect: 'none',
                    transform: snapshot.isDragging ? 'scale(.6)' : 'scale(1)',
                    transition: 'all .2s ease-in-out',
                  }}
                >
                  <div className="position-absolute w-100 h-100 p-5 d-flex align-items-center justify-content-center">
                    <button
                      style={{ all: 'unset', top: 7, left: 10, cursor: 'move' }}
                      className="position-absolute text-primary"
                      {...provided.dragHandleProps}
                    >
                      <FontAwesomeIcon icon={faUpDownLeftRight} />
                    </button>

                    <button
                      style={{ all: 'unset', top: 5, right: 10, fontSize: 22 }}
                      className="position-absolute text-primary"
                    >
                      <FontAwesomeIcon icon={faEllipsisVertical} />
                    </button>

                    <div className="d-flex flex-column align-items-center justify-content-center">
                      <div className="text-primary" style={{ fontSize: 42 }}>
                        <FontAwesomeIcon icon={faFileLines} />
                      </div>
                      <Link to={'/' + name} className="text-decoration-none">
                        <span className="fw-bold text-center text-primary">
                          {name}
                        </span>
                      </Link>
                    </div>

                    <button
                      style={{
                        all: 'unset',
                        position: 'absolute',
                        bottom: 5,
                        right: 15,
                        cursor: 'pointer',
                      }}
                      className="text-primary"
                    >
                      <FontAwesomeIcon icon={faCloudArrowDown} />
                    </button>
                  </div>

                  <svg
                    className="w-100 h-100"
                    width="255"
                    height="178"
                    viewBox="0 0 255 178"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <rect width="255" height="178" rx="16" fill="#FBFBFC" />
                  </svg>
                </div>
              </div>
            )}
          </Draggable>
          {provided.placeholder}
        </div>
      )}
    </Droppable>
  )
}

I've noticed that when I remove the index prop from the Draggable component, the automatic movement issue is resolved, but then I encounter the "index prop" error. The issue appears to be related to how I'm handling the index prop and the drag-and-drop operation.

I have tried checking the data structure, using stable IDs, updating the order on drag end, and ensuring unique droppable IDs, but the issue persists. How can I properly handle the index prop and drag-and-drop operation to resolve these issues?

Any insights or suggestions would be greatly appreciated. Thank you!

0 Answers0