Search code examples
reactjsreact-hooksreact-dnd

Drag and drop not working, I'm using react-dnd library


I'm building an application where a list of images is available at the left sidebar, and on the right, there will be a div where we can drop the images.

I'm using the react-dnd library. I have followed the steps as shown in the docs, but I'm getting the error dropped is not function when I drop an image on the target.

sidebar.js

import React, { useState, createContext } from "react";
import NFTCards from "./NFTCards";
import { NFTDATA } from "../utils/data";
import uuid from "react-uuid";
import SiteLogo from "../widgets/SiteLogo";

export const SelectedNFTContext = createContext({ dropped: null });

function Sidebar() {
  const [nftList, setNftList] = useState([...NFTDATA]);

  const dropped = (id) => {
    console.log(nftList);
    const selectedNFT = nftList.filter((nft, i) => nft.id === id);
    selectedNFT[0].status = "selected";
    setNftList(
      nftList.filter((nft, i) => nft.id !== id).concat(selectedNFT[0])
    );
  };

  const searchNFT = (e) => {};
  return (
    <aside className="w-96" aria-label="Sidebar">
      <div className="overflow-y-auto py-4 px-3 bg-gray-50 rounded h-screen dark:bg-gray-800">
        {/* Sidebar Logo */}
        <a href="/" className="flex items-center text-center pl-2.5 mb-5">
          <SiteLogo className="mr-3 mt-6 h-12 sm:h-7" alt="Site Logo" />
        </a>

        {/* Search Bar */}
        <div>
          <form className="my-16">
            <label
              htmlFor="default-search"
              className="mb-2 text-sm font-medium text-gray-900 sr-only dark:text-gray-300"
            >
              Search
            </label>
            <div className="relative">
              <div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
                <svg
                  aria-hidden="true"
                  className="w-5 h-5 text-gray-500 dark:text-gray-400"
                  fill="none"
                  stroke="currentColor"
                  viewBox="0 0 24 24"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="2"
                    d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
                  ></path>
                </svg>
              </div>
              <input
                onChange={searchNFT}
                type="search"
                id="default-search"
                className="block p-4 pl-10 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
                placeholder="Search NFTs & Collections..."
                required=""
              />
              <button
                type="submit"
                className="text-white absolute right-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-[#14E2B2] dark:text-black dark:hover:bg-blue-700 dark:focus:ring-blue-800"
              >
                Search
              </button>
            </div>
          </form>
        </div>
        <SelectedNFTContext.Provider value={{ dropped }}>
          <div className="space-y-8 ">
            {nftList
              .filter((nft) => nft.status === "unselect")
              .map((nft) => (
                <NFTCards
                  index={nft.id}
                  key={uuid()}
                  id={nft.id}
                  imgURL={nft.imgURL}
                  title={nft.title}
                />
              ))}
          </div>
        </SelectedNFTContext.Provider>
      </div>
    </aside>
  );
}

export default Sidebar;


Droppable.js


import React from "react";
import { useDrop } from "react-dnd";
import AnimatedButton from "../widgets/buttons";
import { SelectedNFTContext } from "./Sidebar";

function Dropabble() {
  const dropped = React.useContext(SelectedNFTContext);
  console.log(dropped);
  const [{ isOver }, dropRef] = useDrop({
    accept: "image",

    drop: (item, monitor) => dropped(item.id),
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
    }),
  });

  return (
    <div>
      <h1 className="text-white ml-32 mt-24 text-4xl">
        Drop here NFTs to Mint
      </h1>
      {/* Drag and Drop */}

      <div
        ref={dropRef}
        className={
          isOver
            ? "w-[50vw] h-[50vh] my-16 ml-32 border-dashed border-8 border-green-500 border-spacing-4"
            : "w-[50vw] h-[50vh]   my-16 ml-32 border-dashed border-8  border-spacing-4"
        }
      ></div>
      <AnimatedButton
        onClickFunc={() => alert("Minted")}
        className="relative bg-background text-2xl px-6 py-2 border-2 border-[#14E2B2] hover:text-black hover:bg-[#14E2B2] hover:transition-all  rounded ml-32 my-6"
        buttonName="Mint"
      />
    </div>
  );
}

export default Dropabble;

nftcards.js

import React from "react";
import { useDrag } from "react-dnd";

// import { NFTDATA } from "../utils/data";

function NFTCards({ index, id, imgURL, title }) {
  const [{ isDragging }, dragRef] = useDrag({
    type: "image",
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging(),
    }),
  });

  return (
    <ul index={index}>
      <li ref={dragRef} className={isDragging ? "border-2 " : "border-0   "}>
        <img
          className=" text-center w-full h-80 bg-cover  object-cover"
          src={imgURL}
          alt={title}
        />
      </li>
    </ul>
  );
}

export default NFTCards;

Please leave a hint where I'm doing wrong or link to the best resource.

Thanks for the help

Link to GitHub repository 👇 Repo Link


Solution

  • You have

    <SelectedNFTContext.Provider value={{ dropped }}>
    

    which set the value of the context to the object {dropped}, and

    const dropped = React.useContext(SelectedNFTContext);
    

    which sets dropped to the value of the context (which is not a function but an object containing a function).

    Either remove one pair of curly braces around dropped in the first place, or add one pair of curly braces around dropped in the second place and it should work.