wagmi 核心 Action 详解:switchConnection 切换当前连接账户
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
switchConnection是@wagmi/core提供的一个核心 Action,用于在已建立的多个连接(connection)之间切换"当前账户"。本文以 switchConnection 官方文档 为骨架,结合仓库源码深入讲解它的调用方式、参数与返回类型、底层实现原理、错误处理以及 TanStack Query 与 React Hook 的集成方式,帮助你准确掌握多账户场景下的连接切换能力。
一、switchConnection 是什么
在 wagmi 中,一个Config实例可以同时维护多个"连接"(connection),每个连接对应一个 Connector(如 MetaMask、WalletConnect)与一组账户。switchConnection的作用就是改变当前激活的连接,从而让后续以"当前账户"为基准的读取与交易操作切换到另一套账户上。
从源码看,它的核心逻辑非常精简,位于 packages/core/src/actions/switchConnection.ts:
export async function switchConnection<config extends Config>( config: config, parameters: SwitchConnectionParameters, ): Promise<SwitchConnectionReturnType<config>> { const { connector } = parameters const connection = config.state.connections.get(connector.uid) if (!connection) throw new ConnectorNotConnectedError() await config.storage?.setItem('recentConnectorId', connector.id) config.setState((x) => ({ ...x, current: connector.uid, })) return { accounts: connection.accounts, chainId: connection.chainId, } }它并不负责发起新的钱包连接,而是从config.state.connections这个连接池中取出目标 connector 对应的连接,将其uid设为state.current,从而完成"当前账户"的切换。
二、导入与基本用法
1. 导入
switchConnection从@wagmi/core顶层导出,可直接按需引入:
import { switchConnection } from '@wagmi/core'对应的类型(参数、返回、错误)同样从@wagmi/core导出,将在后文逐一说明。
2. 标准用法
官方文档给出的典型场景是:先通过getConnections拿到当前 Config 上已建立的所有连接,再把其中一个连接对应的 connector 传给switchConnection:
import { getConnections, switchConnection } from '@wagmi/core' import { config } from './config' const connections = getConnections(config) const result = await switchConnection(config, { connector: connections[0]?.connector, })这里的config是一个通过createConfig创建的配置实例,仓库中对应的示例位于 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(), }, })3. 为什么要配合 getConnections
switchConnection的参数是connector,而连接是按connector.uid索引的。getConnections会返回当前 Config 上全部已建立的连接(packages/core/src/actions/getConnections.ts):
export function getConnections(config: Config): GetConnectionsReturnType { const connections = [...config.state.connections.values()] if (config.state.status === 'reconnecting') return previousConnections if (deepEqual(previousConnections, connections)) return previousConnections previousConnections = connections return connections }因此标准姿势就是"先getConnections枚举,再switchConnection指定其中一个",保证传入的 connector 一定处于已连接状态。
三、参数详解
SwitchConnectionParameters
import { type SwitchConnectionParameters } from '@wagmi/core'该类型定义在 packages/core/src/actions/switchConnection.ts:
export type SwitchConnectionParameters = { connector: Connector }connector
- 类型:
Connector - 含义:要切换到的连接对应的 Connector 实例,即 Connector 中描述的对象。
一个实际的使用示例(文档原样):
import { getConnections, switchConnection } from '@wagmi/core' import { config } from './config' const connections = getConnections(config) const result = await switchConnection(config, { connector: connections[0]?.connector, // [!code focus] })需要特别注意的是:connector必须是已经建立过连接的 connector。如果传入的连接并不存在于config.state.connections中,switchConnection会直接抛出ConnectorNotConnectedError(详见下文"错误处理"小节)。如果需要建立全新连接,应使用 connect 之类的 Action,而不是switchConnection。
四、返回类型详解
SwitchConnectionReturnType
import { type SwitchConnectionReturnType } from '@wagmi/core'类型定义于 packages/core/src/actions/switchConnection.ts:
export type SwitchConnectionReturnType<config extends Config = Config> = { accounts: readonly [Address, ...Address[]] chainId: | config['chains'][number]['id'] | (number extends config['chains'][number]['id'] ? number : number & {}) }accounts
- 类型:
readonly [Address, ...Address[]] - 含义:目标 connector 连接上的账户地址列表,至少包含一个地址。它与
getConnection返回的addresses一致,来源于连接建立时获取的账户集合。
chainId
- 类型:
number - 含义:目标 connector 当前所在的链 ID。在类型层面,它会尽量收紧为
config配置中声明的链 ID 联合类型;若 Config 未限定链集合,则退化为number。
需要说明的是,accounts与chainId都是从已有连接中原样返回的(对应源码中的connection.accounts与connection.chainId),switchConnection本身不会发起网络请求去重新查询链与账户。
五、错误处理
import { type SwitchConnectionErrorType } from '@wagmi/core'该联合类型在 packages/core/src/actions/switchConnection.ts 中定义:
export type SwitchConnectionErrorType = | ConnectorNotConnectedErrorType | BaseError | ErrorTypeConnectorNotConnectedError
这是switchConnection最典型的失败场景:当传入的 connector 在config.state.connections中找不到对应连接时抛出。其定义位于 packages/core/src/errors/config.ts:
export type ConnectorNotConnectedErrorType = ConnectorNotConnectedError & { name: 'ConnectorNotConnectedError' } export class ConnectorNotConnectedError extends BaseError { override name = 'ConnectorNotConnectedError' constructor() { super('Connector not connected.') } }即错误信息为Connector not connected.。因此在调用前建议先用getConnections校验目标 connector 是否已连接,避免依赖运行时抛错。
其他错误
BaseError:wagmi 内部所有错误的基类,涵盖连接过程中的通用异常;ErrorType:用于承接任意未知错误(通常由 connector 内部抛出)。
实际开发中可结合getConnection(packages/core/src/actions/getConnection.ts)返回的status字段判断当前连接状态,再决定是否需要先connect再switchConnection。
六、底层实现原理
switchConnection虽然只有十几行代码,但每一步都有明确的语义,值得逐一拆解:
- 校验连接存在:
config.state.connections.get(connector.uid)按 connector 的唯一标识uid在连接池中查找;找不到则抛ConnectorNotConnectedError。 - 持久化最近使用的 connector:
config.storage?.setItem('recentConnectorId', connector.id)会把本次切换的 connector 写入存储。这样在页面刷新或重新连接(reconnect)时,wagmi 可以优先恢复这个最近使用的连接,实现"记住上次使用的钱包"。 - 更新当前连接指针:
config.setState把state.current更新为目标 connector 的uid,同时保留其余 state 字段。此后getConnection(config)会基于新的current返回对应连接与账户(getConnection 实现)。 - 返回切换结果:从已有连接对象中取出
accounts与chainId返回,供调用方立即使用。
由于整个过程只涉及内存状态与一次可选的 storage 写入,不经过网络,switchConnection是同步语义下非常轻量的操作(函数本身为async以便与存储层衔接)。
七、与 TanStack Query 的集成
@wagmi/core/query提供了将switchConnection封装为 mutation 的工厂函数,位于 packages/core/src/query/switchConnection.ts:
export function switchConnectionMutationOptions<config extends Config, context>( config: config, options: SwitchConnectionOptions<config, context> = {}, ): SwitchConnectionMutationOptions<config> { return { ...(options.mutation as any), mutationFn(variables) { return switchConnection(config, variables) }, mutationKey: ['switchConnection'], } }要点如下:
mutationFn直接调用核心 Action,因此语义与手写调用完全一致;mutationKey固定为['switchConnection'],便于在 TanStack Query DevTools 中定位;- 同时导出了一组类型:
SwitchConnectionData(返回类型)、SwitchConnectionVariables(参数类型)、SwitchConnectionMutate/SwitchConnectionMutateAsync(同步/异步触发函数类型)、SwitchConnectionErrorType(错误类型)。
官方文档中的标准导入方式如下:
import { type SwitchConnectionData, type SwitchConnectionVariables, type SwitchConnectionMutate, type SwitchConnectionMutateAsync, SwitchConnectionMutationOptions, } from '@wagmi/core/query'八、React 中的 useSwitchConnection
在 React 侧,wagmi 提供了现成 Hook useSwitchConnection,内部正是基于上面的switchConnectionMutationOptions与 TanStack Query 的useMutation构建:
export function useSwitchConnection< config extends Config = ResolvedRegister['config'], context = unknown, >( parameters: UseSwitchConnectionParameters<config, context> = {}, ): UseSwitchConnectionReturnType<config, context> { const config = useConfig(parameters) const options = switchConnectionMutationOptions(config, parameters) const mutation = useMutation(options) ... }值得注意的兼容性细节:该 Hook 的返回类型中保留了几个标记为@deprecated的别名(packages/react/src/hooks/useSwitchConnection.ts#L39-L48):
/** @deprecated use `useConnections` instead */ connectors: readonly Connector[] /** @deprecated use `mutate` instead */ switchAccount: SwitchConnectionMutate<config, context> /** @deprecated use `mutateAsync` instead */ switchAccountAsync: SwitchConnectionMutateAsync<config, context> /** @deprecated use `mutate` instead */ switchConnection: SwitchConnectionMutate<config, context> /** @deprecated use `mutateAsync` instead */ switchConnectionAsync: SwitchConnectionMutateAsync<config, context>这说明了三个重要信息:
- 当前推荐的用法是直接使用
mutate/mutateAsync触发切换,使用useConnections读取连接列表; - 旧的
switchAccount、switchConnection等字段仅为向后兼容保留,新代码不应再依赖; - 触发时只需传入
{ connector }变量即可,例如:
const { mutateAsync } = useSwitchConnection() await mutateAsync({ connector })九、测试用例验证
仓库为switchConnection提供了完整的单元测试,见 packages/core/src/actions/switchConnection.test.ts,核心场景是"在多个已连接账户之间来回切换":
await connect(config, { connector: connector2 }) await connect(config, { connector: connector1 }) const address1 = getConnection(config).address await switchConnection(config, { connector: connector2 }) const address2 = getConnection(config).address expect(address2).toBeDefined() expect(address1).not.toBe(address2) await switchConnection(config, { connector: connector1 }) const address3 = getConnection(config).address expect(address3).toBeDefined() expect(address1).toBe(address3)测试揭示了三个可以写进实战经验的行为:
switchConnection只会改变"当前账户",而不会断开其他连接——两个连接在切换后依然并存;- 切换后
getConnection(config).address会立即反映新账户; - 切回原 connector 后,账户地址与切换前完全一致(
address1 === address3),说明连接状态被完整保留。
十、典型应用场景小结
结合文档与源码,switchConnection最适合以下场景:
- 多钱包/多账户 DApp:用户在界面上下拉选择"使用哪个账户操作",切换后所有依赖
getConnection/useAccount的组件自动响应; - 记住最近使用:通过底层写入
recentConnectorId的机制,配合连接恢复流程,让用户下次进入时自动回到上次使用的连接; - 作为 mutation 接入数据层:借助
switchConnectionMutationOptions或useSwitchConnection,将切换动作纳入 TanStack Query 的加载/错误状态管理。
需要再次强调的是:switchConnection只负责切换已存在的连接;如果目标 connector 尚未连接,应当先调用 connect,否则会得到ConnectorNotConnectedError。这一约束是使用该 Action 时最容易踩的坑,也是文档示例中坚持先getConnections再切换的根本原因。
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考