Ethers.js vs Wagmi 的差异
文章目录
- 前言
- 🔍 **Ethers.js vs Wagmi 的差异**
- **Ethers.js 方式(旧实现)**
- **Wagmi 方式(现代实现)**
- 🎯 **关键差异**
- **1. Signer 管理**
- **2. Provider 选择**
- **3. 错误处理**
- 🚀 **为什么 Wagmi 不需要 getSigner?**
- **只读操作 (readContract)**
- **写入操作 (writeContract)**
- ⚡ **优势对比**
- 💡 **现在的实现更简洁**
- 还有很多重要差异!
- 🔧 **技术架构差异**
- **1. 类型安全**
- **2. 响应式数据**
- 🌐 **网络处理差异**
- **3. 多链支持**
- **4. RPC 故障转移**
- 📊 **状态管理差异**
- **5. 缓存策略**
- **6. 实时更新**
- 🔐 **安全性差异**
- **7. 地址验证**
- **8. 交易确认**
- 🎨 **开发体验差异**
- **9. 错误处理**
- **10. 调试支持**
- 📱 **移动端支持**
- **11. 钱包连接**
- 📈 **性能差异**
- **12. 请求优化**
前言
Ethers.js 和 Wagmi 之间的区别:
🔍 Ethers.js vs Wagmi 的差异
Ethers.js 方式(旧实现)
// 需要手动管理 provider 和 signer
const provider = new ethers.BrowserProvider(window.ethereum)
const signer = await provider.getSigner() // 需要获取签名者
const contract = new ethers.Contract(address, abi, signer)
const result = await contract.getAllTokenIds(address)
Wagmi 方式(现代实现)
// Wagmi 自动管理连接和签名
const result = await readContract(wagmiConfig, {address: contractAddress,abi: contractAbi,functionName: 'getAllTokenIds',args: [userAddress]
})
🎯 关键差异
1. Signer 管理
- Ethers.js: 需要手动
getSigner()
- Wagmi: 自动使用当前连接的钱包
2. Provider 选择
- Ethers.js: 需要判断
window.ethereum
存在性 - Wagmi: 自动处理钱包连接状态
3. 错误处理
- Ethers.js: 手动处理各种错误情况
- Wagmi: 内置错误处理和重试机制
🚀 为什么 Wagmi 不需要 getSigner?
只读操作 (readContract)
// getAllTokenIds 是 view 函数,只读操作
// Wagmi 使用公共 RPC 节点,不需要签名
await readContract(config, {functionName: 'getAllTokenIds' // view function
})
写入操作 (writeContract)
// 转账等操作需要签名,Wagmi 自动处理
await writeContract(config, {functionName: 'transferFrom' // 需要签名的操作
})
⚡ 优势对比
特性 | Ethers.js | Wagmi |
---|---|---|
代码量 | 更多 | 更少 |
错误处理 | 手动 | 自动 |
钱包连接 | 手动管理 | 自动管理 |
网络切换 | 手动处理 | 自动处理 |
缓存 | 无 | 内置 |
重试机制 | 手动 | 自动 |
💡 现在的实现更简洁
你当前的 Wagmi 实现已经比 Ethers.js 版本简洁很多:
// 旧的 Ethers.js: ~20 行代码
// 新的 Wagmi: ~5 行代码
const result = await readContract(wagmiAdapter.wagmiConfig, {address: GIFT_CONTRACT_ADDRESS,abi: giftAbi,functionName: 'getAllTokenIds',args: [ownerAddress],
})
总结: Wagmi 把复杂的钱包管理、签名获取、网络处理都封装了,所以不需要手动 getSigner()
!🎯
还有很多重要差异!
🔧 技术架构差异
1. 类型安全
// Ethers.js - 较少类型提示
const contract = new ethers.Contract(address, abi, signer)
const result = await contract.getAllTokenIds(address) // any 类型// Wagmi - 强类型支持
const result = await readContract(config, {address: '0x...' as `0x${string}`, // 严格地址格式abi: contractAbi,functionName: 'getAllTokenIds', // 从 ABI 推断args: [address], // 参数类型检查
}) // 返回值类型推断
2. 响应式数据
// Ethers.js - 手动状态管理
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [data, setData] = useState(null)// Wagmi - 内置响应式
const { data, isLoading, error } = useReadContract({address: contractAddress,abi: contractAbi,functionName: 'getAllTokenIds',
})
🌐 网络处理差异
3. 多链支持
// Ethers.js - 手动网络管理
if (network.chainId !== 97) {await window.ethereum.request({method: 'wallet_switchEthereumChain',params: [{ chainId: '0x61' }],})
}// Wagmi - 自动网络处理
// 配置多个网络,自动切换和错误处理
const config = createConfig({chains: [bsc, bscTestnet, mainnet],// 自动处理网络切换
})
4. RPC 故障转移
// Ethers.js - 单一 RPC
const provider = new ethers.JsonRpcProvider('https://rpc1.com')// Wagmi - 多 RPC 自动故障转移
transports: {[bsc.id]: fallback([http('https://rpc1.com'),http('https://rpc2.com'), // 自动切换http('https://rpc3.com'),])
}
📊 状态管理差异
5. 缓存策略
// Ethers.js - 无缓存
const balance1 = await contract.balanceOf(address) // 网络请求
const balance2 = await contract.balanceOf(address) // 再次网络请求// Wagmi - 智能缓存
const { data: balance1 } = useReadContract({...}) // 网络请求
const { data: balance2 } = useReadContract({...}) // 使用缓存
6. 实时更新
// Ethers.js - 手动轮询
setInterval(async () => {const newBalance = await contract.balanceOf(address)setBalance(newBalance)
}, 5000)// Wagmi - 智能轮询
const { data } = useReadContract({// ...query: {refetchInterval: 5000, // 自动轮询refetchOnWindowFocus: true, // 窗口聚焦时刷新}
})
🔐 安全性差异
7. 地址验证
// Ethers.js - 手动验证
if (!ethers.isAddress(address)) {throw new Error('Invalid address')
}// Wagmi - 内置验证
address: '0x...' as `0x${string}` // TypeScript 编译时检查
8. 交易确认
// Ethers.js - 手动等待确认
const tx = await contract.transfer(to, amount)
await tx.wait() // 手动等待
const receipt = await provider.getTransactionReceipt(tx.hash)// Wagmi - 自动处理
const { writeContract } = useWriteContract()
const { waitForTransactionReceipt } = useWaitForTransactionReceipt()await writeContract({...}) // 自动等待和确认
🎨 开发体验差异
9. 错误处理
// Ethers.js - 手动错误分类
catch (error) {if (error.code === 'UNPREDICTABLE_GAS_LIMIT') {// 手动处理} else if (error.message.includes('user rejected')) {// 手动处理}
}// Wagmi - 结构化错误
const { error } = useWriteContract()
if (error?.name === 'UserRejectedRequestError') {// 类型化错误处理
}
10. 调试支持
// Ethers.js - 基础日志
console.log('Transaction hash:', tx.hash)// Wagmi - 丰富调试信息
import { http } from 'viem'
const transport = http('...', {onFetchRequest: (request) => console.log('Request:', request),onFetchResponse: (response) => console.log('Response:', response),
})
📱 移动端支持
11. 钱包连接
// Ethers.js - 基础支持
if (window.ethereum) {await window.ethereum.request({method: 'eth_requestAccounts'})
}// Wagmi - 多钱包支持
const config = createConfig({connectors: [walletConnect({...}), // WalletConnectcoinbaseWallet({...}), // Coinbaseinjected({...}), // MetaMask 等]
})
📈 性能差异
12. 请求优化
// Ethers.js - 每次都发请求
const name = await contract.name()
const symbol = await contract.symbol()
const decimals = await contract.decimals()// Wagmi - 批量请求
const { data } = useReadContracts({contracts: [{ ...contractConfig, functionName: 'name' },{ ...contractConfig, functionName: 'symbol' },{ ...contractConfig, functionName: 'decimals' },]
}) // 单次网络请求
总结: Wagmi 在类型安全、状态管理、网络处理、缓存策略、错误处理等方面都比 Ethers.js 更先进!🚀