Я создаю приложение, в котором список изображений доступен на левой боковой панели, а справа будет div, куда мы можем поместить изображения.
Я использую библиотеку react-dnd
. Я выполнил шаги, как показано в docs
, но я получаю сообщение об ошибке dropped
не работает, когда я помещаю изображение на цель.
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.info(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.info(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;
Пожалуйста, оставьте подсказку, где я делаю неправильно, или ссылку на лучший ресурс.
Спасибо за помощь
Ссылка на репозиторий GitHub 👇 Ссылка на репо
У тебя есть
<SelectedNFTContext.Provider value = {{ dropped }}>
которые устанавливают значение контекста для объекта {dropped}
,
и
const dropped = React.useContext(SelectedNFTContext);
который устанавливает dropped
значение контекста (который является не функцией, а объектом, содержащим функцию).
Либо удалите одну пару фигурных скобок вокруг dropped
во-первых, либо добавьте одну пару фигурных скобок вокруг dropped
во-вторых, и это должно работать.
Где вы используете компонент Droppable
? Я не вижу этого нигде в коде, который вы разместили.
Я добавил ссылку на репо выше, или вы можете проверить код здесь 👉 github.com/TheRemora/remora/tree/main/client
Похоже, вы используете его в src/pages/MintNFTPage.js
, но вне Sidebar
, то есть вне провайдера. Так что неудивительно, что useContext
не работает, только компоненты внутри провайдера имеют доступ к значению, определенному в провайдере.
Ох, ну ладно. Что я могу сделать здесь, чтобы решить проблему? Должен ли я обернуть компонент Droppable внутри mintnftpage
, если я оберну его, он не сможет получить доступ к функции dropped
, присутствующей внутри sidebar.js
Вы можете переместить и функцию dropped
, и состояние nftList
в MintNFTPage
.
Я переместил в the mintnftpage.js
все, кроме компонента NFTCards
. Не могли бы вы проверить этот скриншот -> i.imgur.com/lbvCaB6.png
Я добавил фигурные скобки внутри
droppable.js.
const {dropped} = React.useContext(SelectedNFTContext)
Но это не работает