wagmi について
Ethereumアプリ開発者向けに、Wagmi 3.xのReactフックの使い方を案内するスキルです。設定、型安全なコントラクト操作、Reactでよくある問題を扱い、バージョン固有の情報も含みます。
主な機能
- 01Wagmi v3の設定とProvider
- 02ウォレット接続とアカウント用フック
- 03コントラクト読み書き用フック
- 04ABIの型安全性に関する指針
- 05Reactフックと状態管理の注意点
- 06v2からv3への移行情報
活用シーン
- 01ReactアプリでのWagmi設定
- 02ウォレット接続とアカウント情報の取得
- 03Ethereumコントラクトの読み書き
- 04Wagmi v2コードの更新
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ 0xsardius/ onchain-typescript-skills --skill wagmiインストール後、Claude Code で/wagmiを入力して読み込まれたか確認します。
同梱ファイルreferences/hooks-guide.mdreferences/react-patterns.md
詳細
Wagmi スキル
バージョン: Wagmi 3.x | 公式ドキュメント | TypeScript 5.7.3 以降が必要です
Wagmi は Ethereum 向けの React フックを提供します。このスキルでは、プロバイダーの設定、フックの使用方法、React 固有の注意点について、適切なパターンを説明します。
クイックセットアップ(Wagmi v3)
1. 設定
// config.ts
import { http, createConfig } from 'wagmi'
import { mainnet, polygon, arbitrum } from 'wagmi/chains'
// v3: Install connectors separately: npm i @wagmi/connectors
import { injected, coinbaseWallet, walletConnect } from '@wagmi/connectors'
export const config = createConfig({
chains: [mainnet, polygon, arbitrum],
connectors: [
injected(),
coinbaseWallet({ appName: 'My App' }),
walletConnect({ projectId: 'YOUR_PROJECT_ID' }),
],
transports: {
[mainnet.id]: http('https://eth-mainnet.g.alchemy.com/v2/KEY'),
[polygon.id]: http('https://polygon-mainnet.g.alchemy.com/v2/KEY'),
[arbitrum.id]: http('https://arb-mainnet.g.alchemy.com/v2/KEY'),
},
})
v3 の注意点: 依存関係をより適切に管理できるよう、コネクターは
@wagmi/connectorsパッケージに移動しました。
2. プロバイダーの設定
// providers.tsx
'use client' // Required for Next.js App Router
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { config } from './config'
const queryClient = new QueryClient()
export function Providers({ children }: { children: React.ReactNode }) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
)
}
コアフック
useAccount
import { useAccount } from 'wagmi'
function Profile() {
const { address, isConnected, isConnecting, chain } = useAccount()
if (isConnecting) return <div>Connecting...</div>
if (!isConnected) return <div>Not connected</div>
return <div>Connected: {address} on {chain?.name}</div>
}
useConnect / useDisconnect / useConnectors
import { useAccount, useConnect, useDisconnect, useConnectors } from 'wagmi'
function ConnectButton() {
// v3: Use useConnectors() hook instead of getting from useConnect()
const connectors = useConnectors()
const { connect, isPending } = useConnect()
const { disconnect } = useDisconnect()
const { isConnected } = useAccount()
if (isConnected) {
return <button onClick={() => disconnect()}>Disconnect</button>
}
return (
<div>
{connectors.map((connector) => (
<button
key={connector.id}
onClick={() => connect({ connector })}
disabled={isPending}
>
{connector.name}
</button>
))}
</div>
)
}
useReadContract(useContractRead を置き換えます)
import { useReadContract } from 'wagmi'
function Balance() {
const { data, isLoading, error, refetch } = useReadContract({
address: '0x...',
abi, // Use `as const` for type safety
functionName: 'balanceOf',
args: ['0x...'],
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return <div>Balance: {data?.toString()}</div>
}
useWriteContract(useContractWrite を置き換えます)
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
function Transfer() {
const { data: hash, writeContract, isPending, error } = useWriteContract()
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
hash,
})
async function handleTransfer() {
writeContract({
address: '0x...',
abi,
functionName: 'transfer',
args: ['0x...', 1000n],
})
}
return (
<div>
<button onClick={handleTransfer} disabled={isPending}>
{isPending ? 'Confirming...' : 'Transfer'}
</button>
{isConfirming && <div>Waiting for confirmation...</div>}
{isSuccess && <div>Transaction confirmed!</div>}
{error && <div>Error: {error.message}</div>}
</div>
)
}
重要なパターン
ABI の型安全性(重要)
// ✅ CORRECT - as const for full type inference
const abi = [
{
name: 'transfer',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
outputs: [{ name: '', type: 'bool' }],
},
] as const
// ❌ WRONG - no type inference
const abi = [{ ... }] // Missing `as const`
条件付きフック呼び出し(条件付きにしてはいけません)
// ❌ WRONG - Violates Rules of Hooks
function BadComponent({ shouldFetch }) {
if (shouldFetch) {
const { data } = useReadContract({ ... })
}
}
// ✅ CORRECT - Use enabled option
function GoodComponent({ shouldFetch }) {
const { data } = useReadContract({
...params,
query: { enabled: shouldFetch },
})
}
古いクロージャーの防止
// ❌ WRONG - Captures stale values
function BadComponent() {
const [amount, setAmount] = useState(0n)
const { writeContract } = useWriteContract()
// This captures `amount` at render time!
const handleClick = () => {
writeContract({
...params,
args: [amount], // May be stale!
})
}
}
// ✅ CORRECT - Pass fresh values
function GoodComponent() {
const [amount, setAmount] = useState(0n)
const { writeContract } = useWriteContract()
const handleClick = () => {
writeContract({
...params,
args: [amount], // Fresh from closure
})
}
}
よくある間違い
| 間違い | 修正方法 |
|---|---|
| useContractRead(v1) | useReadContract を使用します |
| useContractWrite(v1) | useWriteContract を使用します |
useConnect(v2)からの connectors | useConnectors() フック(v3)を使用します |
useSwitchChain(v2)からの chains | useChains() フック(v3)を使用します |
| 条件付きフック | query: { enabled: bool } を使用します |
| QueryClientProvider の不足 | Wagmi には TanStack Query が必要です |
| hash を待機していない | useWaitForTransactionReceipt を使用します |
| 文字列の数量 | BigInt を使用します:1000n |
wagmi/connectors からのコネクター | @wagmi/connectors パッケージ(v3)を使用します |
参考資料
詳細なパターンについては、以下を参照してください:
references/hooks-guide.md- フックの完全なリファレンスreferences/react-patterns.md- React 固有のパターンと SSR- Wagmi ドキュメント - 公式ドキュメント
- Wagmi GitHub - ソースとリリース
- v2 から v3 への移行 - 破壊的変更
コメント
Markdown 対応