wagmi 使用教程 - Web3 React Hooks 库

2,675 阅读3分钟

wagmi 使用教程 - Web3 React Hooks 库

简介

wagmi 是一个功能强大的 React Hooks 库,专门用于 Web3 开发。它提供了一套完整的工具来处理与区块链的交互,包括:

  • 钱包连接管理

  • 交易处理

  • 智能合约读写

  • 链上数据查询

本教程将介绍 wagmi 的基础用法和主要功能。

环境准备

在开始之前,确保你的开发环境已经安装了以下工具:

  • Node.js (推荐 v20+)
  • pnpm 或 yarn
  • 代码编辑器 (推荐 VS Code)

首先安装必要的依赖:

pnpm install wagmi viem @tanstack/react-query

项目配置

1. Wagmi 配置

创建 wagmi 配置文件,设置链和钱包连接器:

// config.ts
import { http, createConfig } from "wagmi";
import { mainnet } from "wagmi/chains";
import { injected, metaMask, walletConnect } from "wagmi/connectors";

const projectId = "<WALLETCONNECT_PROJECT_ID>"; // WalletConnect项目ID

export const config = createConfig({
  chains: [mainnet],
  connectors: [injected(), walletConnect({ projectId }), metaMask()],
  transports: {
    [mainnet.id]: http(),
  },
});

2. Provider 配置

// App.tsx
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { config } from "./config";

const queryClient = new QueryClient();

function App() {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        {/* 应用组件 */}
      </QueryClientProvider>
    </WagmiProvider>
  );
}

基础功能实现

钱包连接

连接钱包是 Web3 应用的第一步。以下是一个基础的钱包连接组件:

// WalletConnect.tsx
import { useAccount, useConnect, useDisconnect } from "wagmi";

export function WalletConnect() {
  const { address } = useAccount();
  const { connectors, connect } = useConnect();
  const { disconnect } = useDisconnect();

  if (address)
    return (
      <div>
        <div>已连接钱包: {address}</div>
        <button onClick={() => disconnect()}>断开连接</button>
      </div>
    );

  return (
    <div>
      {connectors.map((connector) => (
        <button key={connector.uid} onClick={() => connect({ connector })}>
          连接 {connector.name}
        </button>
      ))}
    </div>
  );
}

发送交易

发送 ETH 交易的示例组件:

// SendTransaction.tsx
import { parseEther } from "viem";
import { useSendTransaction, useWaitForTransactionReceipt } from "wagmi";

export function SendTransaction() {
  const { data: hash, isPending, sendTransaction } = useSendTransaction();

  const { isLoading: isConfirming, isSuccess: isConfirmed } =
    useWaitForTransactionReceipt({
      hash,
    });

  async function submit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);
    const to = formData.get("address") as `0x${string}`;
    const value = formData.get("value") as string;

    sendTransaction({
      to,
      value: parseEther(value),
    });
  }

  return (
    <form onSubmit={submit}>
      <input name="address" placeholder="接收地址" required />
      <input name="value" placeholder="ETH数量" required />
      <button disabled={isPending}>{isPending ? "确认中..." : "发送"}</button>
      {hash && <div>交易哈希: {hash}</div>}
      {isConfirming && <div>等待确认...</div>}
      {isConfirmed && <div>交易已确认</div>}
    </form>
  );
}

合约交互

读取合约数据:

从智能合约读取数据的示例:

// ReadContract.tsx
import { useReadContract } from "wagmi";

const contractConfig = {
  address: "0x...",
  abi: [
    {
      name: "balanceOf",
      type: "function",
      inputs: [{ name: "owner", type: "address" }],
      outputs: [{ type: "uint256" }],
    },
  ],
} as const;

export function ReadContract() {
  const { data: balance, isPending } = useReadContract({
    ...contractConfig,
    functionName: "balanceOf",
    args: ["0x..."], // 查询地址
  });

  if (isPending) return <div>加载中...</div>;

  return <div>余额: {balance?.toString()}</div>;
}
写入合约:

调用合约写入方法的示例:

// WriteContract.tsx
import { useWriteContract, useWaitForTransactionReceipt } from "wagmi";

const contractConfig = {
  address: "0x...",
  abi: [
    {
      name: "mint",
      type: "function",
      inputs: [{ name: "tokenId", type: "uint256" }],
    },
  ],
} as const;

export function WriteContract() {
  const { data: hash, isPending, writeContract } = useWriteContract();

  const { isLoading: isConfirming, isSuccess: isConfirmed } =
    useWaitForTransactionReceipt({
      hash,
    });

  async function mint(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);
    const tokenId = formData.get("tokenId") as string;

    writeContract({
      ...contractConfig,
      functionName: "mint",
      args: [BigInt(tokenId)],
    });
  }

  return (
    <form onSubmit={mint}>
      <input name="tokenId" placeholder="Token ID" required />
      <button disabled={isPending}>{isPending ? "确认中..." : "Mint"}</button>
      {hash && <div>交易哈希: {hash}</div>}
      {isConfirming && <div>等待确认...</div>}
      {isConfirmed && <div>交易已确认</div>}
    </form>
  );
}

最佳实践

1. 错误处理

  • 对所有可能的错误进行捕获和处理
  • 为用户提供清晰的错误提示
  • 实现适当的重试机制

2. 用户体验

  • 添加加载状态提示
  • 提供交易确认进度
  • 实现友好的错误提示
  • 添加适当的动画效果

3. 安全考虑

  • 验证用户输入
  • 使用安全的数据类型(如 BigInt)处理金额
  • 实现交易确认提示
  • 添加交易限额检查

4. 性能优化

  • 使用 React Query 进行数据缓存
  • 实现合理的重新请求策略
  • 避免不必要的重渲染

进阶学习

  1. 多链支持
  2. ENS 集成
  3. 签名验证
  4. 交易历史记录
  5. Gas 优化

相关资源

希望这个教程能帮助你开始 Web3 前端开发之旅!如果有任何问题,欢迎继续提问。