如何在React中用Wagmi实现多链钱包余额展示(仿Opensea)
多链余额展示解决方案(基于Wagmi)
要实现多链余额展示,核心是为每个目标链单独调用useBalance钩子并指定对应链的chainId,让Wagmi通过对应链的RPC节点获取余额数据。以下是具体实现方案:
基础实现:循环调用useBalance
直接遍历支持的链,对每个链实例化useBalance并传入chainId参数:
import { useAccount, useBalance } from 'wagmi'; import { BsThreeDotsVertical } from 'react-icons/bs'; import ChainLogos from './ChainLogos'; // 你的链Logo组件 function MultiChainBalance() { const { address, isConnected, connector } = useAccount(); // 过滤掉Goerli测试链,保留目标链 const targetChains = connector?.chains.filter(chain => chain.network !== 'goerli') || []; if (!isConnected) { return <div>请连接钱包</div>; } return ( <div className="multi-chain-container"> {targetChains.map((chain) => { // 为当前链单独请求余额 const { data: balance, isLoading, isError } = useBalance({ address, chainId: chain.id, // 关键:指定当前链的chainId }); return ( <div key={chain.id} className="chain-item"> <div className="chain-info"> <ChainLogos chainId={chain.network} /> <div> <p>{chain.network}</p> <span>{chain.name}</span> </div> </div> <div className="balance-info"> {isLoading ? ( <p>加载中...</p> ) : isError ? ( <p>获取失败</p> ) : ( <div> <p>{balance?.formatted}</p> <span>{balance?.symbol}</span> </div> )} <BsThreeDotsVertical /> </div> </div> ); })} </div> ); }
优化方案:批量查询(减少钩子嵌套)
如果目标链数量较多,可使用Wagmi的useQueries钩子批量处理余额请求,提升代码整洁度:
import { useAccount, useQueries, useWagmiClient } from 'wagmi'; import { BsThreeDotsVertical } from 'react-icons/bs'; import ChainLogos from './ChainLogos'; function MultiChainBalance() { const { address, isConnected, connector } = useAccount(); const client = useWagmiClient(); const targetChains = connector?.chains.filter(chain => chain.network !== 'goerli') || []; // 批量构建余额查询配置 const balanceQueries = targetChains.map(chain => ({ queryKey: ['multi-chain-balance', address, chain.id], queryFn: () => client.getBalance({ address, chainId: chain.id }), enabled: isConnected && !!address, // 仅连接后执行查询 })); // 执行批量查询 const queryResults = useQueries({ queries: balanceQueries }); if (!isConnected) { return <div>请连接钱包</div>; } return ( <div className="multi-chain-container"> {targetChains.map((chain, index) => { const { data: balance, isLoading, isError } = queryResults[index]; return ( <div key={chain.id} className="chain-item"> <div className="chain-info"> <ChainLogos chainId={chain.network} /> <div> <p>{chain.network}</p> <span>{chain.name}</span> </div> </div> <div className="balance-info"> {isLoading ? ( <p>加载中...</p> ) : isError ? ( <p>获取失败</p> ) : ( <div> <p>{balance?.formatted}</p> <span>{balance?.symbol}</span> </div> )} <BsThreeDotsVertical /> </div> </div> ); })} </div> ); }
扩展:添加USD估值
如果需要像Opensea一样显示USD价值,可集成第三方价格API(如CoinGecko):
// 在余额渲染部分添加USD估值 {balance && ( <div> <p>{balance.formatted}</p> <span>{balance.symbol}</span> {/* 新增USD估值 */} <USDValue tokenSymbol={balance.symbol} balance={balance.formatted} /> </div> )} // USD估值组件示例 function USDValue({ tokenSymbol, balance }) { const { data: price } = useQuery({ queryKey: ['token-price', tokenSymbol], queryFn: async () => { const res = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${tokenSymbol.toLowerCase()}&vs_currencies=usd`); const data = await res.json(); return data[tokenSymbol.toLowerCase()]?.usd; }, enabled: !!tokenSymbol, }); if (!price) return null; const usdValue = (parseFloat(balance) * price).toFixed(2); return <span>${usdValue} USD</span>; }
内容的提问来源于stack exchange,提问作者Kehinde Babalola
相关产品推荐
相关产品推荐

