Wagmi v2 & Viem Hooks Guide for React Applications
5 min readAug 6, 2025
Press enter or click to view image in full size![]()
Published by mirtalha
Installation
First, install the required packages:
npm install wagmi viem @tanstack/react-query
# or
yarn add wagmi viem @tanstack/react-queryBasic Setup
1. Configuration Setup
// config/wagmi.js
import { createConfig, http } from 'wagmi'
import { mainnet, sepolia } from 'wagmi/chains'
import { injected, metaMask, safe, walletConnect } from 'wagmi/connectors'
const projectId = 'YOUR_WALLETCONNECT_PROJECT_ID'
export const config = createConfig({
chains: [mainnet, sepolia],
connectors: [
injected(),
walletConnect({ projectId }),
metaMask(),
safe(),
],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
},
})2. App Provider Setup
// App.js
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { config } from './config/wagmi'
const queryClient = new QueryClient()
function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<YourAppComponents />
</QueryClientProvider>
</WagmiProvider>
)
}Core Wagmi v2 Hooks Connection Hooks
useConnect
import { useConnect } from 'wagmi'
function ConnectWallet() {
const { connectors, connect, status, error } = useConnect()
return (
<div>
{connectors.map((connector) => (
<button
key={connector.uid}
onClick={() => connect({ connector })}
disabled={status === 'pending'}
>
{connector.name}
</button>
))}
{error && <div>Error: {error.message}</div>}
</div>
)
}useDisconnect
import { useDisconnect } from 'wagmi'
function DisconnectButton() {
const { disconnect } = useDisconnect()
return <button onClick={() => disconnect()}>Disconnect</button>
}useAccount
import { useAccount } from 'wagmi'
function AccountInfo() {
const { address, isConnected, isConnecting, isDisconnected } = useAccount()
if (isConnecting) return <div>Connecting...</div>
if (isDisconnected) return <div>Disconnected</div>
return (
<div>
<div>Address: {address}</div>
<div>Connected: {isConnected}</div>
</div>
)
}
Balance and Chain Hooks
useBalance
import { useBalance } from 'wagmi'
function Balance() {
const { data: balance, isError, isLoading } = useBalance({
address: '0x...',
})
if (isLoading) return <div>Fetching balance…</div>
if (isError) return <div>Error fetching balance</div>
return (
<div>
Balance: {balance?.formatted} {balance?.symbol}
</div>
)
}useChainId
import { useChainId } from 'wagmi'
function ChainInfo() {
const chainId = useChainId()
return <div>Chain ID: {chainId}</div>
}useSwitchChain
import { useSwitchChain } from 'wagmi'
function SwitchChain() {
const { chains, switchChain } = useSwitchChain()
return (
<div>
{chains.map((chain) => (
<button key={chain.id} onClick={() => switchChain({ chainId: chain.id })}>
Switch to {chain.name}
</button>
))}
</div>
)
}Transaction Hooks
useSendTransaction
import { useSendTransaction } from 'wagmi'
import { parseEther } from 'viem'
function SendTransaction() {
const { data: hash, sendTransaction } = useSendTransaction()
const handleSend = () => {
sendTransaction({
to: '0x...',
value: parseEther('0.01'),
})
}
return (
<div>
<button onClick={handleSend}>Send Transaction</button>
{hash && <div>Transaction Hash: {hash}</div>}
</div>
)
}useWaitForTransactionReceipt
import { useWaitForTransactionReceipt } from 'wagmi'
function TransactionStatus({ hash }) {
const { data: receipt, isLoading, isSuccess } = useWaitForTransactionReceipt({
hash,
})
return (
<div>
{isLoading && <div>Waiting for confirmation...</div>}
{isSuccess && <div>Transaction confirmed!</div>}
{receipt && <div>Block: {receipt.blockNumber}</div>}
</div>
)
}Contract Interaction Hooks
useReadContract
import { useReadContract } from 'wagmi'
const contractABI = [
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
},
]
function TokenBalance() {
const { data: balance } = useReadContract({
address: '0x...', // Token contract address
abi: contractABI,
functionName: 'balanceOf',
args: ['0x...'], // User address
})
return <div>Token Balance: {balance?.toString()}</div>
}useWriteContract
import { useWriteContract } from 'wagmi'
function WriteContract() {
const { data: hash, writeContract } = useWriteContract()
const handleWrite = () => {
writeContract({
address: '0x...',
abi: contractABI,
functionName: 'transfer',
args: ['0x...', 1000n],
})
}
return (
<div>
<button onClick={handleWrite}>Transfer Tokens</button>
{hash && <div>Transaction: {hash}</div>}
</div>
)
}useSimulateContract
import { useSimulateContract, useWriteContract } from 'wagmi'
function SafeContractWrite() {
const { data: simulateData } = useSimulateContract({
address: '0x...',
abi: contractABI,
functionName: 'transfer',
args: ['0x...', 1000n],
})
const { writeContract } = useWriteContract()
const handleWrite = () => {
writeContract(simulateData!.request)
}
return (
<button
onClick={handleWrite}
disabled={!simulateData}
>
Safe Transfer
</button>
)
}Event Hooks
useWatchContractEvent
import { useWatchContractEvent } from 'wagmi'
function EventWatcher() {
useWatchContractEvent({
address: '0x...',
abi: contractABI,
eventName: 'Transfer',
onLogs(logs) {
console.log('New transfer events!', logs)
},
})
return <div>Watching for Transfer events...</div>
}Advanced Patterns
Custom Hook for Token Operations
import { useReadContract, useWriteContract, useSimulateContract } from 'wagmi'
function useToken(tokenAddress) {
const { data: name } = useReadContract({
address: tokenAddress,
abi: erc20ABI,
functionName: 'name',
})
const { data: symbol } = useReadContract({
address: tokenAddress,
abi: erc20ABI,
functionName: 'symbol',
})
const { writeContract: transfer } = useWriteContract()
const transferToken = (to, amount) => {
transfer({
address: tokenAddress,
abi: erc20ABI,
functionName: 'transfer',
args: [to, amount],
})
}
return {
name,
symbol,
transferToken,
}
}Get mirbasit01’s stories in your inbox
Join Medium for free to get updates from this writer.
Error Handling Pattern
import { useAccount, useConnect } from 'wagmi'
function WalletConnection() {
const { address, isConnected } = useAccount()
const { connect, connectors, error, isLoading } = useConnect()
if (error) {
return (
<div className="error">
Failed to connect: {error.message}
</div>
)
}
if (isConnected) {
return <div>Connected to {address}</div>
}
return (
<div>
{connectors.map((connector) => (
<button
key={connector.uid}
onClick={() => connect({ connector })}
disabled={isLoading}
>
{isLoading ? 'Connecting...' : `Connect ${connector.name}`}
</button>
))}
</div>
)
}Complete Example Component
import { useState } from 'react'
import {
useAccount,
useConnect,
useDisconnect,
useBalance,
useSendTransaction,
useWaitForTransactionReceipt
} from 'wagmi'
import { parseEther, formatEther } from 'viem'
function WalletApp() {
const [recipient, setRecipient] = useState('')
const [amount, setAmount] = useState('')
const { address, isConnected } = useAccount()
const { connectors, connect } = useConnect()
const { disconnect } = useDisconnect()
const { data: balance } = useBalance({ address })
const { data: hash, sendTransaction } = useSendTransaction()
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash })
const handleSend = (e) => {
e.preventDefault()
sendTransaction({
to: recipient,
value: parseEther(amount),
})
}
if (!isConnected) {
return (
<div>
<h2>Connect Wallet</h2>
{connectors.map((connector) => (
<button
key={connector.uid}
onClick={() => connect({ connector })}
>
Connect {connector.name}
</button>
))}
</div>
)
}
return (
<div>
<div>
<h2>Wallet Connected</h2>
<p>Address: {address}</p>
<p>Balance: {balance ? formatEther(balance.value) : '0'} ETH</p>
<button onClick={() => disconnect()}>Disconnect</button>
</div>
<form onSubmit={handleSend}>
<h3>Send Transaction</h3>
<input
type="text"
placeholder="Recipient address"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
/>
<input
type="text"
placeholder="Amount in ETH"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<button type="submit" disabled={isConfirming}>
{isConfirming ? 'Confirming...' : 'Send'}
</button>
</form>
{hash && <div>Transaction Hash: {hash}</div>}
{isConfirming && <div>Waiting for confirmation...</div>}
{isSuccess && <div>Transaction confirmed!</div>}
</div>
)
}Key Changes in Wagmi v2
- New Import Structure: Import directly from ‘wagmi’ instead of ‘wagmi/actions’
- Simplified Configuration: Use
createConfiginstead ofconfigureChains - Better TypeScript Support: Enhanced type inference
- Improved Performance: Better caching and optimization
- Viem Integration: Direct viem utilities usage (parseEther, formatEther, etc.)
Best Practices
- Always handle loading and error states
- Use simulation before writing to contracts
- Implement proper error boundaries
- Cache contract ABIs appropriately
- Use TypeScript for better development experience
- Test with different wallet connectors
- Handle network switching gracefully
Main Features Covered:
- Complete setup with providers and configuration
- All essential hooks for wallet connection, balance checking, transactions
- Contract interaction hooks (read, write, simulate)
- Event watching and transaction monitoring
- Error handling patterns
Key wagmi v2 Hooks:
useConnect,useDisconnect,useAccount- wallet managementuseBalance,useChainId,useSwitchChain- blockchain datauseSendTransaction,useWaitForTransactionReceipt- transactionsuseReadContract,useWriteContract,useSimulateContract- smart contractsuseWatchContractEvent- event monitoring
Important Changes in v2:
- Simplified configuration with
createConfig - Direct integration with viem utilities
- Better TypeScript support
- Improved performance and caching
- Performance Optimization Tips — Shows how to optimize re-renders and batch contract reads
- Real-World Production Patterns — Multi-chain support and transaction queue management
- Testing Strategies — Mock setup and integration testing examples
- Security Best Practices — Input validation and rate limiting
- Migration Guide — Clear v1 to v2 migration examples
- Common Pitfalls — What to avoid and best practices
- Resources & Next Steps — Useful links and community resources









