wagmi
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWagmi Skill
Wagmi 技能
Version: Wagmi 3.x | Official Docs | Requires TypeScript 5.7.3+
Wagmi provides React hooks for Ethereum. This skill ensures correct patterns for provider setup, hooks usage, and React-specific pitfalls.
版本: Wagmi 3.x | 官方文档 | 要求TypeScript 5.7.3+
Wagmi 为Ethereum提供React Hooks。本技能确保Provider配置、Hooks使用以及React特有陷阱的正确处理模式。
Quick Setup (Wagmi v3)
快速上手(Wagmi v3)
1. Config Setup
1. 配置设置
typescript
// 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 Note: Connectors are now inpackage for better dependency control.@wagmi/connectors
typescript
// 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 注意事项: Connectors现在位于包中,以实现更优的依赖管理。@wagmi/connectors
2. Provider Setup
2. Provider配置
tsx
// 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>
)
}tsx
// 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>
)
}Core Hooks
核心Hooks
useAccount
useAccount
tsx
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>
}tsx
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
useConnect / useDisconnect / useConnectors
tsx
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>
)
}tsx
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 (REPLACES useContractRead)
useReadContract(替代useContractRead)
tsx
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>
}tsx
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 (REPLACES useContractWrite)
useWriteContract(替代useContractWrite)
tsx
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>
)
}tsx
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>
)
}Critical Patterns
关键模式
ABI Type Safety (CRITICAL)
ABI类型安全(至关重要)
typescript
// ✅ 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`typescript
// ✅ 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`Conditional Hook Calls (NEVER conditional)
条件式Hook调用(绝对禁止)
tsx
// ❌ 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 },
})
}tsx
// ❌ 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 },
})
}Stale Closure Prevention
避免陈旧闭包
tsx
// ❌ 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
})
}
}tsx
// ❌ 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
})
}
}Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
| useContractRead (v1) | Use |
| useContractWrite (v1) | Use |
| Use |
| Use |
| Conditional hooks | Use |
| Missing QueryClientProvider | Wagmi requires TanStack Query |
| Not awaiting hash | Use |
| String amounts | Use BigInt: |
Connectors from | Use |
| 错误 | 修复方案 |
|---|---|
| useContractRead (v1) | 使用 |
| useContractWrite (v1) | 使用 |
| 从useConnect获取connectors (v2) | 使用 |
| 从useSwitchChain获取chains (v2) | 使用 |
| 条件式调用Hooks | 使用 |
| 缺少QueryClientProvider | Wagmi依赖TanStack Query |
| 未等待交易哈希确认 | 使用 |
| 使用字符串表示金额 | 使用BigInt: |
从 | 使用 |
References
参考资料
For detailed patterns, see:
- - Complete hooks reference
references/hooks-guide.md - - React-specific patterns and SSR
references/react-patterns.md - Wagmi Documentation - Official docs
- Wagmi GitHub - Source and releases
- v2 to v3 Migration - Breaking changes
如需详细模式说明,请参阅:
- - 完整Hooks参考
references/hooks-guide.md - - React特有模式及SSR
references/react-patterns.md - Wagmi官方文档 - 官方文档
- Wagmi GitHub - 源码与发行版
- v2至v3迁移指南 - 破坏性变更