wagmi 的 useConnectors Hook 完全指南:读取与响应式订阅已配置的连接器
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
useConnectors是 wagmi React 包中用于获取已配置连接器(Connectors)的核心 Hook。本文围绕 useConnectors.md 文档展开,结合 wagmi 仓库源码(React Hook 实现、core 层 Action 与测试用例),系统讲解其导入方式、基本用法、返回类型、底层响应式原理以及在钱包连接 UI 中的实战应用,帮助读者在 React 应用中准确获取并实时跟踪连接器列表的变化。
什么是 useConnectors
在 wagmi 中,"连接器"(Connector)是应用与钱包(如 MetaMask、WalletConnect、Coinbase Wallet 等)之间的桥梁,负责建立连接、管理账户状态与链上交互。这些连接器由createConfig在创建配置时统一注册,useConnectors则负责在 React 组件中读取这份注册表。
useConnectors是面向 React 的 Hook,它本质上是对 core 层getConnectorsAction 的 React 封装:内部通过useSyncExternalStore订阅连接器存储(store),一旦连接器集合发生变化(例如动态添加了新的连接器),组件会自动重新渲染并拿到最新列表。
对应文档:site/react/api/hooks/useConnectors.md
Import:如何导入 useConnectors
与 wagmi 的其他 React Hooks 一样,useConnectors直接从wagmi包导入:
import { useConnectors } from 'wagmi'Hook 源码位于 packages/react/src/hooks/useConnectors.ts,文件首行声明了'use client',表明它只能在客户端组件环境中使用——这一点在使用 Next.js App Router 等 SSR 框架时需要特别注意,避免在服务端渲染阶段调用。
如果你使用的是框架适配包(Solid / Vue),对应的实现分别为 packages/solid/src/primitives/useConnectors.ts 与 packages/vue/src/composables/useConnectors.ts,API 语义保持一致。
Usage:在组件中获取连接器列表
最基本的使用方式是在任意组件内调用 Hook,直接获得connectors数组:
import { useConnectors } from 'wagmi' function App() { const connectors = useConnectors() // connectors 为 readonly Connector[],可遍历渲染钱包列表 return ( <ul> {connectors.map((connector) => ( <li key={connector.uid}>{connector.name}</li> ))} </ul> ) }注意,useConnectors只是读取"已配置的连接器",它不会触发任何连接动作。典型的场景是把返回结果交给useConnect的connectors参数,从而渲染出一个钱包选择列表,用户点击某个钱包后再真正发起连接。参考 React 指南 connect-wallet.md。
使用该 Hook 需要先通过createConfig建立配置并提供给WagmiProvider。一个最小可用的配置如下(对应 config.ts):
import { createConfig, http } from 'wagmi' import { mainnet, sepolia } from 'wagmi/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })在上面的配置中未显式传入connectors,此时 wagmi 会使用默认的injected连接器(即浏览器内置钱包,如 MetaMask 扩展)。若要注册多个钱包,可在createConfig中通过connectors选项传入连接器工厂函数数组,例如:
import { createConfig, http } from 'wagmi' import { mainnet } from 'wagmi/chains' import { injected } from 'wagmi/connectors' import { metaMask } from 'wagmi/connectors' import { walletConnect } from 'wagmi/connectors' export const config = createConfig({ chains: [mainnet], connectors: [ injected(), metaMask(), walletConnect({ projectId: 'YOUR_PROJECT_ID' }), ], transports: { [mainnet.id]: http(), }, })此时useConnectors()返回的数组将包含这三个连接器实例。在 packages/core/src/createConfig.ts 中可以看到,createConfig会遍历rest.connectors中每个工厂函数并调用它们,将生成的连接器实例统一存入内部的 connector store。
Return Type:返回类型详解
文档中给出的返回类型声明为:
import { type UseConnectorsReturnType } from 'wagmi'其实际类型为readonly Connector[],即只读的连接器数组,元素是Connector实例,数据来源是config.connectors(createConfig内部 connector store 的状态)。
从源码 packages/react/src/hooks/useConnectors.ts 可以看到,React 层直接复用了 core 的类型:
export type UseConnectorsParameters<config extends Config = Config> = ConfigParameter<config> export type UseConnectorsReturnType<config extends Config = Config> = GetConnectorsReturnType<config>而GetConnectorsReturnType在 packages/core/src/actions/getConnectors.ts 中定义为:
export type GetConnectorsReturnType<config extends Config = Config> = config['connectors']也就是说,Hook 的返回类型与createConfig的泛型配置强关联,config['connectors']本身就是readonly Connector[]形态,TypeScript 可以根据配置自动推导出精确的数组类型,无需手动标注。
可选参数:config
useConnectors接受一个可选的参数对象{ config },用于在未包裹WagmiProvider的场景下显式传入配置实例。源码中的useConfig(parameters)会优先取参数里的config,否则从 Context 中读取。测试用例 useConnectors.test.ts 验证了这一点:
test('parameters: config', async () => { const { result } = await renderHook(() => useConnectors({ config }), { wrapper: ({ children }) => createElement(Fragment, { children }), }) expect(result.current).toBeDefined() })该测试使用Fragment作为 wrapper(即不提供WagmiProvider),证实了通过{ config }参数传入配置时 Hook 同样可以正常工作。
Action:底层对应的 getConnectors
useConnectors对应的底层 Action 是getConnectors,它属于 core 包,可从@wagmi/core导入:
import { getConnectors } from '@wagmi/core' import { config } from './config' const connectors = getConnectors(config)对应文档:site/core/api/actions/getConnectors.md。两者的返回类型完全一致(readonly Connector[]),差别仅在于:getConnectors是一次性读取,而useConnectors额外提供了响应式订阅能力。
引用缓存(Reference Caching)优化
值得注意的细节是,getConnectors.ts 对返回值做了引用级缓存:
let previousConnectors: readonly Connector[] = [] export function getConnectors<config extends Config>( config: config, ): GetConnectorsReturnType<config> { const connectors = config.connectors if ( previousConnectors.length === connectors.length && previousConnectors.every( (connector, index) => connector === connectors[index], ) ) return previousConnectors previousConnectors = connectors return connectors }只要连接器数组的长度不变、且每个元素引用一致,就复用上一次的数组引用。这一优化对 React 的渲染性能很重要:它保证在连接器未发生变化时,useConnectors每次返回的是同一引用,从而避免触发无关组件的无意义重渲染。核心测试 getConnectors.test.ts 连续两次调用并断言结果与config.connectors相等,验证了返回值的一致性。
响应式原理:useSyncExternalStore + watchConnectors
useConnectors之所以能"实时反映"连接器变化,是因为它结合了 React 18 的useSyncExternalStore与 core 层的watchConnectorsAction。完整实现如下(useConnectors.ts):
return useSyncExternalStore( (onChange) => watchConnectors(config, { onChange }), () => getConnectors(config), () => getConnectors(config), )其中useSyncExternalStore的三个参数分别是:订阅函数(subscribe)、读取快照函数(getSnapshot)与服务端渲染快照函数(getServerSnapshot)。这里订阅与快照读取均复用了 SSR 安全的实现,意味着该 Hook 天然兼容服务端渲染场景。
订阅的核心在 core 层的 watchConnectors.ts:
export function watchConnectors<config extends Config>( config: config, parameters: WatchConnectorsParameters<config>, ): WatchConnectorsReturnType { const { onChange } = parameters return config._internal.connectors.subscribe((connectors, prevConnectors) => { onChange(Object.values(connectors), prevConnectors) }) }可以看到watchConnectors直接订阅了config._internal.connectors这个内部 store(其实现位于 createConfig.ts,暴露了setState与subscribe接口)。一旦有人通过setState更新连接器集合,订阅回调就会被触发,进而驱动 React 重新渲染。
动态连接器的场景
尽管大多数应用中连接器列表在创建配置后就固定不变,但 wagmi 的 store 设计允许在运行时动态追加连接器。测试用例 useConnectors.test.ts 演示了这一场景:
test('default', async () => { const { result, rerender } = await renderHook(() => useConnectors()) const count = config.connectors.length expect(result.current.length).toBe(count) expect(result.current).toEqual(config.connectors) config._internal.connectors.setState(() => [ ...config.connectors, config._internal.connectors.setup(mock({ accounts })), ]) rerender() expect(result.current.length).toBe(count + 1) })该测试先断言初始返回的连接器数量与config.connectors一致,随后向内部 store 追加一个 mock 连接器并触发重渲染,最终断言useConnectors返回的数组长度增加了 1。这从侧面验证了 Hook 的响应式更新链路:store 状态变更 → watchConnectors 订阅回调 → useSyncExternalStore 触发重渲染 → 返回新连接器数组。
实战:结合 useConnect 渲染钱包选择器
useConnectors最常见的实战形态是与useConnect搭配,渲染一个钱包选择列表。示例:
import { useConnect, useConnectors } from 'wagmi' function WalletList() { const connectors = useConnectors() const { connect, status } = useConnect() return ( <ul> {connectors.map((connector) => ( <li key={connector.uid}> <button disabled={status === 'pending'} onClick={() => connect({ connector })} > {connector.name} </button> </li> ))} </ul> ) }几点实操提示:
- key 的选择:优先使用
connector.uid作为列表key,它是每个连接器实例的唯一标识;若连接器可能重复注册,使用uid比name更安全。 - 只读数组:返回类型为
readonly Connector[],不能直接对数组进行push/splice等修改操作;若需要派生新数组,请先浅拷贝(如[...connectors])。 - SSR 环境:Hook 声明为
'use client',在 Next.js 等框架中请将其放在客户端组件中调用;其内部同时提供getServerSnapshot,可在服务端渲染时安全地输出快照。 - 连接器属性:每个
Connector实例上可通过connector.name、connector.id等元数据渲染钱包品牌信息,但具体展示效果取决于连接器实现。
小结
useConnectors是 wagmi React 体系中读取已配置连接器的标准入口,核心要点可总结为:
| 维度 | 说明 |
|---|---|
| 导入 | import { useConnectors } from 'wagmi' |
| 返回类型 | readonly Connector[](即UseConnectorsReturnType) |
| 数据来源 | createConfig中注册的config.connectors |
| 底层 Action | getConnectors(一次性读取,含引用缓存) |
| 响应式机制 | useSyncExternalStore+watchConnectors订阅内部 store |
| 常用搭配 | 与useConnect结合渲染钱包选择列表 |
| 框架适配 | 同语义实现见 packages/solid/src/primitives/useConnectors.ts 与 packages/vue/src/composables/useConnectors.ts |
阅读完本文后,你可以通过查看 packages/react/src/hooks/useConnectors.ts、packages/core/src/actions/getConnectors.ts、packages/core/src/actions/watchConnectors.ts 及其对应测试文件,深入理解该 Hook 的完整实现链路。
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考