Skip to main content

🎨 创建铸币用户界面

现在我们成功创建了代币和非同质化代币(NFT),让我们继续着手构建我们的铸币用户界面。这样一来,我们就能直观地与智能合约互动,并允许他人在我们的浏览器上铸造我们的NFT。是不是非常酷?你可能已经注意到,你的网站上现有一个名为 minting 的按钮,但它目前尚未实现任何功能。让我们从定义一个函数开始,然后添加逻辑来允许我们铸造NFT。如果你没有起始代码,可以在这里克隆。

首先,我们将以下代码添加到你的 newMint.tsx 文件中。注意:不要盲目地复制粘贴代码。我只提供了必要的部分,你需要明白这些代码应放在何处。提示:应该放在 Container 元素下方。

// 你的其余代码
import { Button, Text, HStack } from "@chakra-ui/react";
import { MouseEventHandler, useCallback } from "react";
import { ArrowForwardIcon } from "@chakra-ui/icons";

const Home: NextPage = () => {
const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
async (event) => {},
[]
);

return (
<MainLayout>
{/* 你的其余代码 */}
<Image src="" alt="" />
<Button
bgColor="accent"
color="white"
maxWidth="380px"
onClick={handleClick}
>
<HStack>
<Text>stake my buildoor</Text>
<ArrowForwardIcon />
</HStack>
</Button>
</MainLayout>
);
};

完成后,我们可以进入 Connected.tsx 并添加一些代码。在 handleClick 函数上方,我们可以添加 const router = useRouter()。记得在文件顶部导入 useRouter 函数。然后,在你的 handleClick 函数中添加 router.push("/newMint")。现在它应该是这个样子。

const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
async (event) => {
if (event.defaultPrevented) return;
if (!walletAdapter.connected || !candyMachine) return;

try {
setIsMinting(true);
const nft = await metaplex
.candyMachinesV2()
.mint({ candyMachine });

console.log(nft);
router.push(`/newMint?mint=${nft.nft.address.toBase58()}`);
} catch (error) {
alert(error);
} finally {
setIsMinting(false);
}
},
[metaplex, walletAdapter, candyMachine]
);

现在,当你点击 stake my buildoor 按钮时,将提示你从幽灵钱包批准交易。但是,你可能会注意到一旦成功批准交易,页面会刷新并导致你的钱包被登出。别担心,下一部分我们将解决这个问题。

接下来,请前往 newMint.tsx。我们将创建一个接口来解决这个问题。将此代码添加到你的 Home 函数之上。

import { PublicKey } from "@solana/web3.js";

interface NewMintProps {
mint: PublicKey;
}

一旦完成,你应该看到以下代码结构。

// 你的其余代码
import { PublicKey } from "@solana/web3.js";
import { Metaplex, walletAdapterIdentity } from "@metaplex-foundation/js";

interface NewMintProps {
mint: PublicKey;
}

const Home: NextPage<NewMintProps> = ({ mint }) => {
const [metadata, setMetadata] = useState<any>()
const { connection } = useConnection()
const walletAdapter = useWallet()
const metaplex = useMemo(() => {
return Metaplex.make(connection).use(walletAdapterIdentity(walletAdapter))
}, [connection, walletAdapter])

useEffect(() => {
// What this does is to allow us to find the NFT object
// based on the given mint address
metaplex.nfts().findByMint({ mintAddress: new PublicKey(mint) })
.then((nft) => {
// We then fetch the NFT uri to fetch the NFT metadata
fetch(nft.uri)
.then((res) => res.json())
.then((metadata) => {
setMetadata(metadata)
})
})
}, [mint, metaplex, walletAdapter])
};

注意到我们是如何在上述函数中调用 setMetadata(metadata) 的吗?这是为了让我们能够将元数据对象设置为状态,以便我们可以用它来渲染图像。现在让我们在 Image 元素中使用此对象。

<Image src={metadata?.image ?? ""} alt="" />

我们快完成了。如果你现在尝试铸造一个新的NFT,你可能会注意到网站会抛出一个错误,说它无法读取未定义的属性。我们可以通过在底部添加以下几行代码来修复这个问题。

NewMint.getInitialProps = async ({ query }) => {
const { mint } = query;
if (!mint) throw { error: "No mint" };

try {
const mintPubkey = new PublicKey(mint);
return { mint: mintPubkey };
} catch {
throws({ error: "Invalid mint" });
}
};

太棒了!现在你已经添加了所有必要的代码,你应该可以铸造一个NFT,并看到该图像。这就是我看到的样子。

🛠️小修复

请注意网站未能准确显示内容,为了解决这个问题,我们需要前往 WalletContextProvider.tsx 并修改一些代码。

改变

const phantom = new PhantomWalletAdapter();

to

const phantom = useMemo(() => new PhantomWalletAdapter(), []);

我们还需要给你的 autoConnect 添加一个属性。就像这样。

<WalletProvider wallets={[phantom]} autoConnect={true}>
<WalletModalProvider>{children}</WalletModalProvider>
</WalletProvider>

我们需要使用 useMemo 的原因是为了防止钱包适配器被多次构建。你可以在这里了解更多关于useMemo的信息。