You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 资产,无需手动解析链上数据。

步骤:

  1. 安装依赖:
npm install @metaplex-foundation/js @solana/web3.js
  1. 实现 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 13:25:17