React开发非营利组织NFT捐赠应用:Phantom钱包NFT获取与捐赠实现
React 实现 Phantom 钱包连接与 NFT 捐赠功能
下面是针对你的需求的具体实现步骤和代码示例,全部基于 React 和 Solana/Metaplex 生态:
一、连接 Phantom 钱包
Phantom 会在浏览器中注入 window.solana 对象,直接通过这个对象就能完成连接、状态监听等操作,无需额外安装复杂的适配器(当然用 @solana/wallet-adapter-react 也可以,这里用原生方式更直观)。
核心代码实现
import { useState, useEffect } from 'react'; export default function WalletConnector() { const [publicKey, setPublicKey] = useState(null); const [isConnected, setIsConnected] = useState(false); // 监听钱包连接/断开事件,页面加载时检查已连接状态 useEffect(() => { if (!window.solana?.isPhantom) return; const handleConnect = () => { setPublicKey(window.solana.publicKey.toString()); setIsConnected(true); }; const handleDisconnect = () => { setPublicKey(null); setIsConnected(false); }; window.solana.on('connect', handleConnect); window.solana.on('disconnect', handleDisconnect); // 页面初始化时检查是否已连接 window.solana.getAccountInfo().then(info => { if (info) { handleConnect(); } }); return () => { window.solana.removeListener('connect', handleConnect); window.solana.removeListener('disconnect', handleDisconnect); }; }, []); const connectWallet = async () => { try { await window.solana.connect(); } catch (err) { console.error('连接钱包失败:', err); } }; const disconnectWallet = async () => { try { await window.solana.disconnect(); } catch (err) { console.error('断开钱包失败:', err); } }; return ( <div className="wallet-connector"> {isConnected ? ( <div> <span>已连接: {publicKey.slice(0, 8)}...{publicKey.slice(-8)}</span> <button onClick={disconnectWallet}>断开连接</button> </div> ) : ( <button onClick={connectWallet} disabled={!window.solana?.isPhantom} > {window.solana?.isPhantom ? '连接 Phantom 钱包' : '请安装 Phantom 钱包'} </button> )} </div> ); }
二、获取用户钱包内的 NFT 数据
Solana 上的 NFT 遵循 Metaplex 标准,用 @metaplex-foundation/js 库可以快速查询用户的 NFT 资产,无需手动解析链上数据。
步骤:
- 安装依赖:
npm install @metaplex-foundation/js @solana/web3.js
- 实现 NFT 列表组件
import { useState, useEffect } from 'react'; import { Metaplex, clusterApiUrl } from '@metaplex-foundation/js'; import { Connection, PublicKey } from '@solana/web3.js'; export default function NftDashboard({ publicKey }) { const [nfts, setNfts] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { if (!publicKey) return; const fetchUserNfts = async () => { setLoading(true); try { // 连接 Solana 测试网,生产环境替换为 mainnet-beta const connection = new Connection(clusterApiUrl('devnet')); const metaplex = Metaplex.make(connection); // 查询用户所有 NFT const userNfts = await metaplex.nfts().findAllByOwner({ owner: new PublicKey(publicKey), }); // 提取前端需要展示的字段 const simplifiedNfts = userNfts.map(nft => ({ mintAddress: nft.address.toString(), name: nft.name, imageUrl: nft.json?.image || nft.metadataUri, description: nft.json?.description || '无描述', })); setNfts(simplifiedNfts); } catch (err) { console.error('获取 NFT 失败:', err); } finally { setLoading(false); } }; fetchUserNfts(); }, [publicKey]); if (loading) return <p>加载 NFT 中...</p>; return ( <div className="nft-grid-container"> <h2>我的可捐赠 NFT</h2> {nfts.length === 0 ? ( <p>钱包中没有可捐赠的 NFT</p> ) : ( <div className="nft-grid"> {nfts.map(nft => ( <div key={nft.mintAddress} className="nft-card"> <img src={nft.imageUrl} alt={nft.name} onError={(e) => e.target.src = 'https://via.placeholder.com/200'} /> <h3>{nft.name}</h3> <p>{nft.description}</p> <button className="donate-btn" onClick={() => handleDonate(nft.mintAddress)} > 捐赠此 NFT </button> </div> ))} </div> )} </div> ); }
三、实现 NFT 捐赠功能
捐赠的本质是将 NFT 的所有权转移到非营利组织的钱包地址,用 Metaplex 的转移方法可以自动处理交易签名、发送和确认。
补充捐赠函数(添加到上面的 NftDashboard 组件中)
const handleDonate = async (mintAddress) => { try { const connection = new Connection(clusterApiUrl('devnet')); // 用已连接的 Phantom 钱包作为签名者 const metaplex = Metaplex.make(connection).use( window.solana // Phantom 钱包适配 Metaplex 的签名器 ); // 替换为你的非营利组织的钱包地址 const recipientPublicKey = new PublicKey('YOUR_NONPROFIT_WALLET_ADDRESS'); const nft = await metaplex.nfts().findByMint({ mintAddress: new PublicKey(mintAddress) }); // 发起 NFT 转移交易 const transferResult = await metaplex.nfts().transfer({ nftOrSft: nft, toOwner: recipientPublicKey, }); // 等待交易上链确认 await transferResult.response.confirmTransaction(); alert('NFT 捐赠成功!感谢你的支持'); // 刷新 NFT 列表 window.location.reload(); } catch (err) { console.error('捐赠失败:', err); alert('捐赠失败,请检查钱包是否授权或网络是否正常'); } };
四、关键注意事项
- 网络一致性:开发时用 Devnet,上线前切换到 Mainnet-beta,确保钱包连接的网络和代码中的网络一致
- 用户授权处理:转移 NFT 需要用户在 Phantom 钱包中确认交易,必须处理用户拒绝授权的异常情况
- 错误提示:给用户清晰的加载、成功、失败提示,提升体验
- 依赖版本:确保
@metaplex-foundation/js和@solana/web3.js是最新稳定版,避免兼容性问题
内容的提问来源于stack exchange,提问作者Delon
相关产品推荐
相关产品推荐

