wagmi Vue 开发指南:useBalance 组合式函数实现原生代币余额查询
2026/9/18 5:01:52 网站建设 项目流程

wagmi Vue 开发指南:useBalance 组合式函数实现原生代币余额查询

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

本篇技术指南聚焦@wagmi/vue包中的useBalance组合式函数(Composable),它是基于 TanStack Query 封装的响应式查询工具,用于在 Vue 应用中获取链上地址的原生币(Native Currency,如 ETH)余额。读完本文,你将掌握useBalance的完整参数体系(地址、区块号、区块标签、链 ID、作用域键等)、查询配置与返回结构,并能从源码层面理解它如何与@wagmi/coregetBalanceaction 协作,最终在真实 Vue 应用中写出可复用的余额查询逻辑。

useBalance 是什么

useBalance@wagmi/vue提供的用于获取原生货币余额(native currency balance)的组合式函数。所谓"原生货币"即链上的基础代币——以太坊主网的 ETH、测试网的测试币、以及任何 EVM 链的 native gas 代币,而非 ERC-20 合约代币(后者应使用useReadContract配合 ERC-20 ABI 查询)。

在 useBalance.ts 源码中,其返回类型定义如下:

export type UseBalanceReturnType<selectData = GetBalanceData> = UseQueryReturnType<selectData, GetBalanceErrorType>

其中GetBalanceData的结构在@wagmi/core的 getBalance action 中定义:

export type GetBalanceReturnType = { decimals: number symbol: string value: bigint }

即每次查询成功后会得到一个包含**小数位数(decimals)、代币符号(symbol)、余额数值(value,以 bigint 表示的最小单位数量)**的对象。以测试用例 useBalance.test.ts 中的断言为例,当查询chain.mainnet2链上某账户余额时,返回{ decimals: 18, symbol: 'WAG', value: 69000000000000000000n },这正是parseEther('69')对应的最小单位数值——value是原始 wei 值,展示时需要结合decimals自行格式化。

安装与导入

useBalance@wagmi/vue包导出,导入方式如下:

import { useBalance } from '@wagmi/vue'

该导出在 exports/index.ts 中登记(第 28 行useBalance,),同时也提供了配套的类型导出:

import { type UseBalanceParameters } from '@wagmi/vue' import { type UseBalanceReturnType } from '@wagmi/vue'

在 Nuxt 等框架集成场景下,useBalance同样被 Nuxt 模块自动桥接导出(见 nuxt/module.ts),可无缝配合自动导入使用。

快速上手:查询一个地址的余额

useBalance最基本的用法是传入一个address,组合式函数会自动从最近的WagmiPlugin提供上下文中取出 Config,并使用当前激活链发起查询:

<!-- index.vue --> <script setup lang="ts"> import { useBalance } from '@wagmi/vue' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', }) </script>

上面的示例依赖一个已经通过WagmiPlugin注册的 wagmi 配置,配置示例参见 config.ts:

import { createConfig, http } from '@wagmi/vue' import { mainnet, sepolia } from '@wagmi/vue/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })

result是一个响应式查询对象,你可以在模板中这样渲染余额:

<template> <div v-if="result.isSuccess"> {{ result.data?.value }} ({{ result.data?.symbol }}) </div> <div v-else-if="result.isPending">加载中…</div> <div v-else-if="result.isError">{{ result.error?.message }}</div> </template>

参数详解

useBalance的参数类型为UseBalanceParameters,它由@wagmi/coreGetBalanceOptionsConfigParameter组合而来,并且通过DeepMaybeRef支持深度响应式参数——这意味着你可以传入ref()包裹的值,组合式函数内部会用deepUnref自动解包(见 useBalance.ts 第 32 行const params = computed(() => deepUnref(parameters)))。各参数说明如下。

address

  • 类型:Address | undefined
  • 说明:要查询余额的地址,必填。当addressundefined时,查询的enabled会被置为false,即查询不会自动执行
<script setup lang="ts"> import { useBalance } from '@wagmi/vue' import { mainnet } from '@wagmi/vue/chains' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', }) </script>

这一"禁用逻辑"在@wagmi/core的 getBalance.ts 查询选项中实现:

enabled: Boolean(options.address && (options.query?.enabled ?? true)),

也正因如此,address是支持响应式"从无到有"的:先传入undefined挂起查询,待地址可用(如用户连接钱包后)再更新,查询会自动启用。测试behavior: address: undefined -> defined(useBalance.test.ts)验证了这一点:初始时fetchStatusidle,设置地址后自动发起查询并成功返回数据。

blockNumber

  • 类型:bigint | undefined
  • 说明:查询指定区块高度处的余额,用于历史快照场景。
<script setup lang="ts"> import { useBalance } from '@wagmi/vue' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', blockNumber: 17829139n, }) </script>

注意blockNumberblockTag互斥:在 getBalance action 中,二者通过三元表达式分别透传给 viem:

const value = await action( blockNumber !== undefined ? { address, blockNumber } : { address, blockTag }, )

即指定了blockNumber就按该区块高度查询,否则按blockTag查询。

blockTag

  • 类型:'latest' | 'earliest' | 'pending' | 'safe' | 'finalized' | undefined
  • 说明:查询指定区块标签处的余额。默认由 viem 使用'latest''safe''finalized'仅在支持相应 RPC 方法的链上可用(如以太坊 PoS 后的合并相关标签)。
<script setup lang="ts"> import { useBalance } from '@wagmi/vue' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', blockTag: 'latest', }) </script>

chainId

  • 类型:config['chains'][number]['id'] | undefined
  • 说明:指定查询目标链的 ID。默认使用useChainId提供的当前激活链;显式传入chainId可以查询与当前链不同的其他链上的余额。
<script setup lang="ts"> import { useBalance } from '@wagmi/vue' import { mainnet } from '@wagmi/vue/chains' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', chainId: mainnet.id, }) </script>

在实现层面(useBalance.ts 第 34-40 行),组合式函数通过useChainId获得当前链 ID,并在组装查询选项时执行chainId: params.value.chainId ?? chainId.value,实现"未指定则回退到当前链"的语义。测试parameters: chainId验证了跨链查询:传入chain.mainnet2.id后得到该测试链上的symbol: 'WAG'与余额值。

config

  • 类型:Config | undefined
  • 说明:显式传入Config以替代从最近的WagmiPlugin上下文自动获取的配置。适用于脱离插件上下文、手动管理配置的场景(如测试、库开发)。
<script setup lang="ts"> import { useBalance } from '@wagmi/vue' import { config } from './config' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', config, }) </script>

scopeKey

  • 类型:string | undefined
  • 说明:将查询缓存限定到指定上下文。具有相同 context(含相同scopeKey及其他参数)的 Hook 会共享同一份缓存,适用于多个组件查询相同数据时避免重复请求,或为不同业务场景隔离缓存。
<script setup lang="ts"> import { useBalance } from '@wagmi/vue' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', scopeKey: 'foo', }) </script>

query 选项

useBalance还支持在query字段中传入 TanStack Query v5 的查询参数(完整列表见 query-options.md 的共享文档),常用的包括:

选项类型说明
enabledboolean \| undefined设为false可禁用查询自动运行;可用于依赖查询场景
gcTimenumber \| Infinity \| undefined未使用/非活跃缓存数据的保留时间,默认5 * 60 * 1000(5 分钟),SSR 期间为Infinity;设为Infinity禁用垃圾回收
staleTimenumber \| Infinity \| undefined数据被视为过期的毫秒数,默认0;设为Infinity则永不过期
refetchIntervalnumber \| false \| function定时轮询间隔(毫秒),可用于余额自动刷新
refetchOnWindowFocusboolean \| 'always' \| function窗口聚焦时是否重新拉取,默认true
retryboolean \| number \| function失败重试策略,客户端默认3次,服务端默认0
retryDelaynumber \| function重试延迟,可传指数退避函数attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)
initialDataTData \| (() => TData) \| undefined初始缓存数据(会被持久化到缓存);默认视为过期,除非设置了staleTime
placeholderDataTData \| function \| undefined挂起状态下的占位数据(不会持久化到缓存)
select(data: TData) => unknown转换/挑选返回数据,只影响组件拿到的data,不影响缓存内容
notifyOnChangePropsstring[] \| 'all' \| function控制组件仅在指定属性变化时重新渲染
networkMode'online' \| 'always' \| 'offlineFirst' \| undefined网络模式,默认'online'
queryClientQueryClient \| undefined使用自定义 QueryClient,否则使用最近上下文中的实例
metaRecord<string, unknown> \| undefined附加到缓存条目的元信息,可在queryFn的上下文中访问

注意:queryFnqueryKey由 wagmi 内部使用,不可覆盖;其余 TanStack Query 参数均可用。

例如,实现"每 15 秒自动刷新余额":

<script setup lang="ts"> import { useBalance } from '@wagmi/vue' const result = useBalance({ address: '0x4557B18E779944BFE9d78A672452331C186a9f48', query: { refetchInterval: 15_000, }, }) </script>

select 转换数据

通过query.select可以直接从查询结果中提取你关心的字段,其类型会随之收窄。类型测试 useBalance.test-d.ts 演示了这一点:

const result = useBalance({ query: { select(data) { return data?.value }, }, }) // result.data 的类型被推断为 Ref<bigint> | Ref<undefined>

返回类型

useBalance的返回值UseBalanceReturnType是 TanStack Query 的响应式结果(UseQueryReturnType),核心字段(完整说明见 query-result.md)如下:

字段类型说明
data{ decimals: number; symbol: string; value: bigint } \| undefined最近一次成功解析的数据,默认undefined
errornull \| GetBalanceErrorType查询抛出的错误对象,默认null
status'error' \| 'pending' \| 'success'查询状态:pending无缓存且未完成、error失败、success成功
fetchStatus'fetching' \| 'idle' \| 'paused'是否正在拉取;fetching表示queryFn执行中,idle表示未拉取
isPending/isError/isSuccessbooleanstatus派生的布尔标识
isLoadingboolean首次拉取进行中,等价于isFetching && isPending
isFetching/isRefetchingboolean是否正在拉取 / 是否在后台重新拉取
isStaleboolean缓存数据是否已失效或超出staleTime
refetchfunction手动重新拉取,可传{ cancelRefetch, throwOnError }
failureCount/failureReasonnumber/null \| error失败次数与失败原因
dataUpdatedAt/errorUpdatedAtnumber数据/错误最近更新时间戳

注意data.value是 bigint 类型的最小单位数值,若要显示为带小数的可读金额,需要结合decimals自行格式化(如使用 viem 的formatUnits)。

底层实现原理

理解useBalance的内部工作方式,有助于排查缓存、链切换与响应式更新等问题。其实现(useBalance.ts)可分为三层:

第一层:Vue 响应式封装。useBalance将入参包在computed(() => deepUnref(parameters))中,从而把ref、嵌套响应式对象等深度解包为普通值;随后通过useConfig(params)获取 Config(若参数中未显式传入config,则从WagmiPlugin上下文获取),通过useChainId({ config })订阅当前链 ID 的变化(见 useChainId.ts,它内部用watchChainId监听链切换并在组件作用域销毁时自动取消订阅)。

第二层:查询选项组装。组合式函数调用getBalanceQueryOptions(config, { ...params, chainId: params.chainId ?? chainId.value })生成 TanStack Query 选项(query/getBalance.ts)。该函数做了两件关键事:

  • 计算enabledBoolean(options.address && (options.query?.enabled ?? true)),地址缺失时整条查询静默禁用;
  • 生成查询键['balance', filterQueryOptions(options)],参数变化会改变查询键,从而触发自动重新请求。

第三层:底层 action 调用。真正发请求的是@wagmi/coregetBalanceaction(actions/getBalance.ts)。它通过config.getClient({ chainId })按链 ID 获取 viem 客户端,再用getAction(client, viem_getBalance, 'getBalance')调用 viem 的getBalance,最后从config.chainsclient.chain中取出该链的nativeCurrency元数据,将 viem 返回的裸数值补充为{ decimals, symbol, value }结构。这也解释了为什么返回值中的symboldecimals来自链配置而非 RPC 响应。

此外,@wagmi/core/query还导出了配套的getBalanceQueryKeygetBalanceQueryOptionsGetBalanceDataGetBalanceOptions等类型与工具(详见 query-imports.md),供需要在 query 层面做更精细控制的进阶场景使用:

import { type GetBalanceData, type GetBalanceOptions, type GetBalanceQueryFnData, type GetBalanceQueryKey, getBalanceQueryKey, getBalanceQueryOptions, } from '@wagmi/vue/query'

测试验证与边界行为

仓库测试(useBalance.test.ts)覆盖了该组合式函数的几个关键行为,可作为使用时的行为参考:

  1. 默认查询:传入address后查询成功,返回结构包含decimalssymbolvalue三个字段。
  2. 链参数:显式传入chainId可查询指定链的余额,返回该链的原生币符号与精确数值。
  3. 地址从无到有address初始为undefined时查询处于idle挂起状态;地址变为有效值后自动启用并成功返回——这正是钱包连接后余额自动加载的典型交互模式。
  4. 缺少必要属性时禁用:仅传地址、缺少其他条件时查询保持idle,不会发起无效请求。

更多资源

  • 底层 action 文档:getBalance
  • 配置对象说明:createConfigWagmiPlugin
  • Vue 组合式函数总览:composables
  • 参考实现源码:useBalance.ts、getBalance.ts、getBalance.ts

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询