wagmi watchBlockNumber 深度实战:监听区块高度变化的完整指南 wagmi watchBlockNumber 深度实战监听区块高度变化的完整指南【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmiwatchBlockNumber是 wagmi Core 提供的高阶 Action用于实时监听链上新区块的产生并在区块高度变化时触发回调。本文以 wagmi 仓库中 watchBlockNumber.md 文档为骨架结合 watchBlockNumber.ts 源码实现与测试用例系统讲解其全部配置参数、类型约束、底层执行原理以及它在 React 框架中的封装用法帮助你写出可靠、可复用的区块监听逻辑。watchBlockNumber 是什么watchBlockNumber是一个观察型watchAction它与getBlockNumber这类一次性查询 Action 不同它会在订阅建立后持续监听区块高度变化每当链上产生新块就把最新的区块号回调给应用。这在需要实时刷新余额、价格、链上状态或实现等待新区块这类业务时非常关键。从 watchBlockNumber.ts 源码 可以看到它本质上是 wagmi 对 viemwatchBlockNumber的封装职责包括根据传入的chainId从config中解析出对应的 viem Client通过getAction工具优先取用 Client 上已扩展的watchBlockNumber实现否则回退到可摇树tree-shakable的 viem 实现在syncConnectedChain开启时额外订阅当前连接链变化事件实现链切换时自动重建监听返回一个清理函数用于停止监听并释放资源。快速上手导入从wagmi/core导入watchBlockNumberimport { watchBlockNumber } from wagmi/core基础用法watchBlockNumber的第一个参数是config由createConfig创建第二个参数是需要提供onBlockNumber回调的配置对象import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, }) unwatch()其中config通过createConfig创建配置示例见 site/snippets/core/config.tsimport { createConfig, http } from wagmi/core import { mainnet, sepolia } from wagmi/core/chains export const config createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })从源码调用约定看watchBlockNumber是命令式imperativeAPI适合在非组件环境如脚本、事件总线、store中使用在 React 组件内更推荐使用封装好的useWatchBlockNumberHook详见后文。参数详解完整参数类型可从wagmi/core导入import { type WatchBlockNumberParameters } from wagmi/core该类型在 watchBlockNumber.ts 中定义是 viemWatchBlockNumberParameters与ChainIdParameter、SyncConnectedChainParameter见 properties.ts交叉组合、并按链做联合展开union的结果。chainId类型config[chains][number][id] | undefined作用指定查询数据所用的链 ID。不传时使用当前连接的链显式传入后可把监听固定在特定链上import { watchBlockNumber } from wagmi/core import { mainnet } from wagmi/core/chains import { config } from ./config const unwatch watchBlockNumber(config, { chainId: mainnet.id, onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, }) unwatch()注意chainId的类型被约束为config[chains][number][id]即必须是config中声明过的链这能在编译期拦截拼写错误或不存在的链 ID。emitOnBegin类型boolean | undefined作用订阅建立时是否立即把当前最新区块号回调一次。这在初始化界面时需要立刻拿到当前高度的场景非常有用避免先查一次再订阅的两步操作import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { emitOnBegin: true, onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, }) unwatch()emitMissed类型boolean | undefined作用是否把监听期间错过的区块号补发给回调例如订阅建立前已经产生、或轮询间隔内产生的多个区块。import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { emitMissed: true, onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, }) unwatch()onBlockNumber类型(blockNumber: bigint, prevBlockNumber: bigint | undefined) void作用区块号变化时触发的回调。第一个参数是新的区块号bigint注意不要直接参与字符串拼接/数值运算第二个参数是上一个区块号首次触发时为undefined。import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, }) unwatch()onError类型((error: Error) void) | undefined作用获取区块号过程中抛出的错误回调。订阅类 API 的错误通常发生在轮询请求失败或 WebSocket 断连时显式处理onError可避免错误被静默吞掉import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, onError(error) { console.error(Block number error, error) }, }) unwatch()poll类型boolean | undefined作用是否使用轮询机制定时请求 RPC代替 WebSocket 订阅来检测新区块。默认值WebSocket Client 默认为false使用订阅非 WebSocket Client 默认为true使用轮询。import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, poll: true, }) unwatch()从类型层面看poll并非在所有传输transport下都可自由取值。在 watchBlockNumber.test-d.ts 的类型测试中对http()传输的 mainnet 链poll类型被收窄为true | undefined因此poll: false会被ts-expect-error标记为编译错误对webSocket()传输的 optimism 链poll类型才是完整的boolean | undefined。也就是说使用 HTTP 传输时轮询是唯一可行方式poll: true而 WebSocket 传输下你既可以用订阅poll: false也可以退回轮询poll: true。pollingInterval类型number | undefined作用轮询频率毫秒。默认值取createConfig时配置的 pollingInterval未配置时 wagmi 内部有兜底默认值。import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, pollingInterval: 1_000, }) unwatch()仅在poll: true时该参数生效区块产出较快或对实时性要求高的链可适当调低间隔同时注意不要低于 RPC 提供方的限频阈值。syncConnectedChain类型boolean | undefined作用是否为当前连接链变化建立订阅即当用户切换连接的链时自动重建区块监听。默认值取 createConfig 的syncConnectedChain源码中createConfig的默认值为true见 createConfig.ts。import { watchBlockNumber } from wagmi/core import { config } from ./config const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { console.log(Block number changed!, blockNumber) }, syncConnectedChain: false, }) unwatch()在源码 watchBlockNumber.ts 中可以看到其默认值处理逻辑syncConnectedChain config._internal.syncConnectedChain。当未显式传入chainId且syncConnectedChain为true时会通过config.subscribe(({ chainId }) chainId, async (chainId) listener(chainId))订阅链切换事件并在链变化后用新链的 Client 重新建立监听见 watchBlockNumber.ts。返回值watchBlockNumber返回一个清理函数类型为WatchBlockNumberReturnTypeimport { type WatchBlockNumberReturnType } from wagmi/core调用该函数会停止区块监听并解除连接链变化订阅释放底层资源。从 源码返回逻辑 看清理函数同时执行unlisten?.()停止当前链的监听与unsubscribe?.()解除链切换订阅。因此在组件卸载、页面离开、任务结束时务必调用unwatch()避免监听泄漏unwatch()是可重复调用的内部对空值做了可选链保护。源码原理监听是如何建立的watchBlockNumber的完整执行流程对应 watchBlockNumber.ts如下解析默认值从parameters中解构syncConnectedChain缺省时取config._internal.syncConnectedChain。建立监听器定义listener(chainId)内部通过config.getClient({ chainId })获取对应链的 viem Client再用getAction取出watchBlockNumber动作执行。getAction见 getAction.ts的优先级是Client 上同名扩展实现 → 显式watchBlockNumber扩展 → 回退到可摇树的 viem 实现。首次启动const unlisten listener(parameters.chainId)用传入的chainId可能为undefined表示当前链立即启动监听。链切换跟随若syncConnectedChain为true且未显式传chainId则订阅config的chainId状态变化链变化时先unwatch()旧监听再对新链listener(chainId)重建监听。这套设计意味着wagmi 侧并不自己实现 RPC 轮询/订阅逻辑而是完全复用 viem 的成熟实现只在其上叠加多链解析 链切换自动重建的框架能力因此行为细节如 WebSocket 断线重连、轮询节奏与 viem 保持一致。测试如何验证监听行为仓库中的 watchBlockNumber.test.ts 给出了标准的验证思路test(default, async () { const blockNumbers: bigint[] [] const unwatch watchBlockNumber(config, { onBlockNumber(blockNumber) { blockNumbers.push(blockNumber) }, }) await testClient.mainnet.mine({ blocks: 1 }) await wait(100) await testClient.mainnet.mine({ blocks: 1 }) await wait(100) await testClient.mainnet.mine({ blocks: 1 }) await vi.waitUntil(() blockNumbers.length 3, { timeout: 10_000 }) expect(blockNumbers.length).toBe(3) unwatch() await wait(100) })它通过testClient.mainnet.mine({ blocks: 1 })主动挖出新区块断言回调被触发 3 次最后调用unwatch()并等待确认监听停止。这为你在自己的项目里写监听类代码的单测提供了可复用的范式。React 中的封装useWatchBlockNumber在 React 应用中无需手动管理unwatch。wagmi React 包提供了useWatchBlockNumberHook源码见 useWatchBlockNumber.ts它内部基于useEffect调用核心的watchBlockNumber并把清理函数作为 effect 的返回组件卸载时自动停止监听。关键设计点自动链同步未显式传chainId时通过useChainId({ config })取当前链 ID并在依赖数组中监听chainId变化自动重建监听useWatchBlockNumber.tsenabled开关enabled: false时不建立监听useWatchBlockNumber.ts回调稳定引用onBlockNumber、onError存入useRefeffect 的依赖数组只包含emitMissed、emitOnBegin、poll、pollingInterval、syncConnectedChain等稳定参数避免内联回调导致重复订阅useWatchBlockNumber.ts。用法示例import { useWatchBlockNumber } from wagmi function BlockNumber() { useWatchBlockNumber({ emitOnBegin: true, onBlockNumber(blockNumber, prevBlockNumber) { console.log(current, blockNumber, prev, prevBlockNumber) }, }) return null }与 Viem 的关系watchBlockNumber的底层能力来自 viem 的watchBlockNumber对应viem/actions的 Public Actionwagmi 通过config.getClient拿到链对应的 Client 后直接委托给 viem 执行。因此viem 支持的onBlockNumber、emitOnBegin、emitMissed、poll、pollingInterval等能力在 wagmi 中全部可用wagmi 额外提供的价值是chainId级的多链解析、syncConnectedChain的链切换自动重建以及config统一管理下的类型推导poll等参数会随传输类型收窄。小结watchBlockNumber是构建实时链上体验的基础设施级 Action。掌握它需要理解四个层面API 层面onBlockNumber是唯一必填参数unwatch()负责资源清理参数层面chainId定链、poll/pollingInterval定轮询策略、emitOnBegin/emitMissed定回调时机、syncConnectedChain定链切换行为原理层面它委托 viem 实现监听自身负责多链解析与链切换重建watchBlockNumber.ts框架层面React 中优先使用 useWatchBlockNumber由其自动处理订阅生命周期。建议在实战中始终配合onError处理网络异常并在组件卸载或任务结束时调用清理函数即可构建稳定、无泄漏的区块监听能力。【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考