wagmi getChainId 全解析:读取与监听当前链 ID 的底层实现与实战指南
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
本篇技术指南围绕 wagmi(Ethereum apps 响应式原语库)核心 actiongetChainId展开,讲解如何在@wagmi/core中读取当前链 ID、其返回类型的类型安全推导,以及config.state.chainId的更新机制与边界行为。阅读完本文,你将掌握getChainId的完整用法、它与createConfig/ 连接(connection)状态的关系,以及 React 侧useChainId与watchChainId的配套监听方案。
getChainId 是什么
getChainId是 wagmi 提供的一个用于获取**当前链 ID(chain ID)**的 action。与链上 RPC 调用不同,它不发起任何网络请求,而是直接读取 WagmiConfig内部的全局状态,属于纯同步的内存操作。
官方文档对其定义只有一句话:Action for getting current chain ID,其完整实现位于 getChainId.ts:
export function getChainId<config extends Config>( config: config, ): GetChainIdReturnType<config> { return config.state.chainId }可以看到,整个函数体只有一行:直接返回config.state.chainId。这是 wagmi 中结构最简单的 action 之一,其价值更多体现在类型系统与状态同步的配合上。
导入与基本用法
从 @wagmi/core 导入
import { getChainId } from '@wagmi/core'getChainId及其返回类型GetChainIdReturnType通过 exports/actions.ts 作为公共 API 导出:
export { type GetChainIdReturnType, getChainId, } from '../actions/getChainId.js'传递 config 调用
getChainId是函数式 action,需要显式传入通过createConfig创建的config实例:
import { getChainId } from '@wagmi/core' import { config } from './config' const chainId = getChainId(config)对应的config示例(来自 site/snippets/core/config.ts):
import { 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(), }, })上述配置声明了mainnet(链 ID 1)与sepolia(链 ID 11155111)两条链,因此getChainId(config)返回的类型会被推导为1 | 11155111的字面量联合类型(见下文“返回类型”)。
返回类型
getChainId的返回类型可独立导入:
import { type GetChainIdReturnType } from '@wagmi/core'其类型定义为:
export type GetChainIdReturnType<config extends Config = Config> = config['chains'][number]['id']即返回值类型被约束为createConfig的chains参数中所有链 ID 的字面量联合。这带来两个类型安全收益:
- 穷尽性检查:对
getChainId(config)的结果做switch分支时,TypeScript 能感知所有可能值; - 跨 action 一致:该类型与
switchChain、getClient等 action 使用同一套链 ID 字面量,避免手写number造成的拼写错误。
运行时层面,返回值为number类型——即config.state.chainId当前存储的数字值。
config.state.chainId 的来源与更新机制
getChainId读取的是config.state.chainId,而这一状态字段由createConfig维护。理解它的生命周期是正确使用getChainId的关键。
初始值:chains 数组的第一个链
在 createConfig.ts 中,getInitialState将chainId初始化为配置的第一条链:
function getInitialState(): State { return { chainId: chains.getState()[0].id, connections: new Map<string, Connection>(), current: null, status: 'disconnected', } }因此在应用启动且尚未连接钱包时,getChainId(config)会返回chains[0].id。以上面的配置为例,即mainnet.id(1)。
连接后:跟随当前 connection 的链
当用户连接钱包后,connect 事件处理 会把data.chainId写入 connection 状态;同时createConfig默认开启的syncConnectedChain(默认true)会订阅当前 connection 的链变化,并在链已配置时同步更新config.state.chainId(见 createConfig.ts):
if (syncConnectedChain) store.subscribe( ({ connections, current }) => current ? connections.get(current)?.chainId : undefined, (chainId) => { const isChainConfigured = chains .getState() .some((x) => x.id === chainId) if (!isChainConfigured) return return store.setState((x) => ({ ...x, chainId: chainId ?? x.chainId, })) }, )注意其中的守卫条件:只有目标链位于chains配置中,才会切换默认链;否则保持原值。
持久化时的合法性校验
config.state.chainId会随 zustandpersist中间件持久化到 storage,但恢复时会通过validatePersistedChainId校验持久化值是否仍属于已配置链,不合法则回退到默认链 ID(见 createConfig.ts):
function validatePersistedChainId(persistedState, defaultChainId) { return persistedState && 'chainId' in persistedState && typeof persistedState.chainId === 'number' && chains.getState().some((x) => x.id === persistedState.chainId) ? persistedState.chainId : defaultChainId }这也印证了官方文档的提示:getChainId只会返回通过createConfig的chains参数配置过的链 ID。
边界行为:连接的链未在 Config 中配置
官方文档明确说明:
如果当前活动连接(connection)的
chainId不属于你的 WagmiConfig中的任何一条链,getChainId将返回最后一个已配置的链 ID。
这与上述syncConnectedChain订阅中的isChainConfigured守卫逻辑完全一致:未配置的链不会覆盖config.state.chainId,因此读取到的是“最近一次配置过的链 ID”,而不是连接钱包的链。
测试验证:状态如何影响返回值
getChainId.test.ts 用两个断言验证了该 action 的行为:
test('default', async () => { expect(getChainId(config)).toEqual(chain.mainnet.id) config.setState((x) => ({ ...x, chainId: chain.mainnet2.id })) expect(getChainId(config)).toEqual(chain.mainnet2.id) })- 初始状态下返回配置的首条链
mainnet.id; - 通过
config.setState改写state.chainId后,getChainId立即返回新值。
这说明getChainId是无副作用、读取即返回的纯函数,其正确性完全由config.state保证。
配套监听:watchChainId 与 useChainId
getChainId本身只做一次性读取。当链切换时(例如用户通过钱包切换网络),需要配合监听机制感知变化。
watchChainId(core 层)
watchChainId.ts 基于config.subscribe实现:
export function watchChainId<config extends Config>( config: config, parameters: WatchChainIdParameters<config>, ): WatchChainIdReturnType { const { onChange } = parameters return config.subscribe((state) => state.chainId, onChange) }回调onChange(chainId, prevChainId)会在state.chainId变化时触发,返回值为取消订阅函数。
useChainId(React 层)
React 封装 useChainId.ts 结合useSyncExternalStore与watchChainId,实现链 ID 的响应式订阅:
return useSyncExternalStore( (onChange) => watchChainId(config, { onChange }), () => getChainId(config), () => getChainId(config), )组件内直接调用useChainId()即可获得当前链 ID,并在链切换时自动触发重渲染——这正是 wagmi“Reactive primitives for Ethereum apps”定位在链元数据读取上的体现。Vue 与 Solid 等框架也提供对应的响应式封装。
常见场景小结
| 场景 | 推荐 API | 说明 |
|---|---|---|
| 一次性读取当前链 ID | getChainId(config) | 同步、无网络请求 |
| 链切换时响应式更新 | watchChainId(config, { onChange }) | core 层订阅,返回退订函数 |
| React 组件内响应式读取 | useChainId() | 基于useSyncExternalStore自动订阅 |
| 读取所有已配置链 | getChains(config) | 配合chains配置做链列表渲染 |
延伸阅读
- createConfig:
chains、syncConnectedChain、storage等参数共同决定config.state.chainId的初始值与更新规则; - getChains:获取
config中配置的全部链对象; - switchChain:发起链切换,会联动更新
config.state.chainId; - 核心实现:getChainId.ts、createConfig.ts、useChainId.ts;
- 测试用例:getChainId.test.ts。
理解getChainId的本质(读取config.state.chainId)与边界(仅返回已配置链 ID、未配置连接回退到最后配置值),能帮助你在多链 DApp 中准确判断“当前处于哪条链”,避免因链配置不完整导致的业务误判。
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考