wagmi 框架适配指南:基于 Wagmi Core 构建 Svelte、Solid.js 等框架的响应式集成
2026/9/17 7:46:49 网站建设 项目流程

wagmi 框架适配指南:基于 Wagmi Core 构建 Svelte、Solid.js 等框架的响应式集成

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

Wagmi Core 是纯 VanillaJS 实现的以太坊交互核心层,天然可以在任意 JavaScript 框架中使用。本文基于 wagmi 仓库中的官方框架适配指南(site/core/guides/framework-adapters.md),系统讲解如何将 Wagmi Core 与 React、Vue 之外的框架(如 Svelte、Solid.js、Angular)做深度集成:包括依赖注入、响应式订阅、TanStack Query 桥接、测试策略与代理导出五个核心主题。读完本文,你将掌握复用 Wagmi Core 的完整方法论,并能在自己的框架里复刻useConnectionuseChainIduseClientuseConnectorClient这类关键原语,让链切换、账户连接等状态变化自动驱动整个应用的 UI 更新。

为什么框架适配是必要的

Wagmi Core 本身不依赖任何框架。从源码结构看,packages/core 中的createConfiggetConnectiongetChainIdwatchConnection等 actions 全部是纯函数式 API,任何框架都可以直接调用。官方文档的答复很明确:你现在就可以用——Wagmi Core 就是一份可嵌入任意框架的 VanillaJS 库。

但对许多开发者来说,这种"裸用"并不够爽快。以 React 和 Vue 为代表的官方框架包(packages/react、packages/vue)之所以体验好,是因为它们把 Core 与框架的响应式系统做了深度绑定:

  • React:通过 Hooks 把状态订阅收敛到组件内,链切换、连接账户后组件自动重渲染;
  • Vue:通过 composables 把同样的能力封装成响应式 ref。

如果你希望 Svelte、Solid.js、Angular 等框架也获得同等的集成体验,就需要自己动手做"适配层"。官方在文档中坦言,核心团队目前没有足够时间高质量地维护更多框架包,但社区成员完全可以主导这项工作——这正是本文要帮你做到的事。

依赖注入:让 Config 贯穿你的框架

为什么需要注入

创建 Wagmi Config 之后,框架内的所有高级函数(React 的 Hooks、Vue 的 composables)都需要访问它。如果不做注入,使用者每次调用都要手动传 Config,体验很差。Wagmi 的做法是通过框架自带的依赖注入机制把 Config 放进全局作用域:

  • React 使用 React Context);
  • Vue 使用app.provide(对应实现见 packages/vue/src/plugin.ts)。

React 的注入实现

packages/react/src/context.ts 中,WagmiContext是一个默认值为undefined的 Context,WagmiProvider通过WagmiContext.Provider把 Config 提供给整棵组件树:

export const WagmiContext = createContext< ResolvedRegister['config'] | undefined >(undefined) export function WagmiProvider(parameters: React.PropsWithChildren<WagmiProviderProps>) { const { children, config } = parameters const props = { value: config } return createElement( Hydrate, parameters, createElement(WagmiContext.Provider, props, children), ) }

而消费端 useConfig 的逻辑非常直白:优先使用显式传入的parameters.config,否则从 Context 中读取;读不到就抛出WagmiProviderNotFoundError

export function useConfig<config extends Config>(parameters = {}) { const config = parameters.config ?? useContext(WagmiContext) if (!config) throw new WagmiProviderNotFoundError() return config }

Vue 的注入实现

packages/vue/src/plugin.ts 用 Symbol 作为注入键,通过 Vue 的插件机制把 Config 挂到应用上:

export const configKey = Symbol() export const WagmiPlugin = { install(app, options) { const { config, reconnectOnMount = true } = options app.provide(configKey, config) const { onMount } = hydrate(config, { ...options, reconnectOnMount }) onMount() }, }

注意 Vue 插件在安装时还会调用hydrateonMount()处理挂载重连(reconnect)与状态水合。在你的框架里,依赖注入这一步要完成两件事:一是让组件/合成函数能拿到 Config;二是在 Config 变化时(比如用户重新创建 Config)让持有方同步更新。

响应式层:订阅 Config 状态变化

核心原则:跟踪 Config 的变化

每个框架的响应式哲学都不同:React 靠不可变状态 + 重渲染,Vue 靠响应式 ref,Solid.js 靠 signal,Svelte 靠编译期响应式。把 Wagmi Core 与框架打通,最关键的一点是:让 Config 的状态变化被框架追踪。只有这样,"切换链"或"连接/断开账户"这类操作才能在整个应用中传播并更新 UI 状态。

Wagmi Core 为此提供了完整的watch*系列订阅 API(都在 packages/core/src/actions 下),它们都基于config.subscribe实现,并返回取消订阅函数:

  • watchConnection:订阅连接状态,内部用deepEqual比较,并单独比对 connector 的iduid
  • watchChainId:订阅当前链 ID,直接取state.chainId
  • watchClient:订阅当前链的 viem Client,用uid做相等性比较;
  • watchConnectors:订阅连接器列表,同样基于deepEqual

官方推荐的四个关键原语

文档特别点名了四个"最值得优先实现"的 Hook,因为它们在生态里被大量复用,是很多内部机制的地基:

原语对应 Core 订阅 API用途
useConnectionwatchConnection/getConnection获取当前账户地址与连接器,几乎所有账户相关逻辑的基础
useChainIdwatchChainId/getChainId获取当前链 ID,驱动链相关查询与切换
useClientwatchClient/getClient获取当前链的 viem Client,是读写链上数据的总入口
useConnectorClientgetConnectorClientQueryOptions获取当前连接器的签名 Client,用于发送交易、签名消息
React 版 useConnection(subscribe + getSnapshot 模式)

useConnection 是标准的"外部 store 接入 React"范式:把watchConnection的订阅函数传给useSyncExternalStoreWithTrackedgetSnapshot返回getConnection(config)

export function useConnection(parameters = {}) { const config = useConfig(parameters) return useSyncExternalStoreWithTracked( (onChange) => watchConnection(config, { onChange }), () => getConnection(config), ) }
React 版 useChainId

useChainId 结构类似,订阅watchChainId,并额外传入getServerSnapshot以便 SSR 场景使用:

export function useChainId(parameters = {}) { const config = useConfig(parameters) return useSyncExternalStore( (onChange) => watchChainId(config, { onChange }), () => getChainId(config), () => getChainId(config), ) }
Solid.js 版 useChainId(signal + effect + cleanup)

有趣的是,wagmi 仓库里其实已经有一个官方维护的 Solid 包(packages/solid),可以作为"框架适配"的绝佳活教材。Solid 版 useChainId 用createSignal保存状态、createEffect建立订阅、onCleanup释放订阅:

export function useChainId(parameters = () => ({})) { const config = useConfig(parameters) const [chainId, setChainId] = createSignal(getChainId(config())) createEffect(() => { const _config = config() setChainId(() => getChainId(_config)) const unsubscribe = watchChainId(_config, { onChange(data) { setChainId(() => data) }, }) onCleanup(() => unsubscribe()) }) return chainId }

注意它的参数是Accessor<SolidParameters<config>>(即() => ({})),返回Accessor<GetChainIdReturnType<config>>——这就是把 Core 的同步 API 翻译成 Solid 响应式访问器的完整思路。从 packages/solid/src/primitives 的useBalanceuseBlockNumber等文件可以看到,useChainId是被大量复用的基础原语。

给你的框架落地时的自查清单

  1. useConnection/useChainId/useClient/useConnectorClient四个原语是否已实现且语义对齐?
  2. 订阅是否在组件/合成函数卸载时正确取消(防止内存泄漏)?
  3. Config 对象本身变化时,是否重新建立订阅(参考 Solid 版在createEffect内重新订阅的做法)?
  4. SSR 场景下是否提供getServerSnapshot之类的同构取值路径?

通过 TanStack Query 获得缓存与去重能力

Wagmi 在 React 和 Vue 中依赖 TanStack Query 实现缓存、请求去重、持久化、重试等能力。好消息是:TanStack Query 不止支持 React/Vue——截至官方文档撰写时,它还支持 Svelte、Solid、Angular。这意味着你不需要为框架另找一套数据请求库,直接用 TanStack Query 的对应 adapter 即可。

@wagmi/core/query导入现成能力

关键入口是'@wagmi/core/query'这个子路径导出。它把 Core 的 action 包装成可直接塞进 TanStack Query 的 query options / mutation functions:

  • 查询类:getBalanceQueryOptionsgetBlockNumberQueryOptionsgetChainIdQueryOptions等;
  • 变更类:connectMutationOptionsdisconnectMutationOptionssendTransactionMutationOptionssignMessageMutationOptions等。

从 packages/core/src/exports/query.ts 可以看到,这些函数从 packages/core/src/query 目录批量 re-export。以getConnectorClientQueryOptions为例,它同时产出了queryKeyqueryFn等完整配置,React 版 useConnectorClient 正是把这份 options 原样交给useQuery

export function useConnectorClient(parameters = {}) { const config = useConfig(parameters) const chainId = useChainId({ config }) const { address, connector } = useConnection({ config }) const options = getConnectorClientQueryOptions(config, { ...parameters, chainId: parameters.chainId ?? chainId, connector: parameters.connector ?? connector, query: parameters.query as any, }) return useQuery(options) as any }

注意useConnectorClient组合了useChainIduseConnection的结果来推导默认参数——这就是文档所说的"连接、链 ID 等原语驱动了大量内部机制"的具体体现。

在你的框架中接入

在你的框架里,安装并配置对应的 TanStack Query adapter(Svelte/Solid/Angular),然后把'@wagmi/core/query'导出的xxxQueryOptions/xxxMutationOptions直接传给 adapter 的useQuery/useMutation等价函数即可,无需重写请求逻辑。

给库作者的泛型提醒

如果你在构建一个面向公众的库,必须正确接好泛型,才能保证类型推断与类型安全。例如上面 React 版的参数类型:

export type UseConnectorClientParameters< config extends Config = Config, chainId extends config['chains'][number]['id'] = config['chains'][number]['id'], selectData = GetConnectorClientData<config, chainId>, > = Compute< GetConnectorClientOptions<config, chainId, selectData> & ConfigParameter<config> >

它把 Core 的GetConnectorClientOptions与框架自身的ConfigParameter交叉组合,既保留了 Core 的完整类型约束,又暴露了框架层的默认参数。想确认自己的泛型接得对不对,最直接的方法就是对照 packages/react/src/hooks 下的既有实现逐项比对。仓库中还提供了 packages/register-tests 这类跨框架类型注册测试,可作为类型安全的参考基准。

测试策略:参照 React 的 Hook 测试

如果你在构建库,测试必不可少。Wagmi 官方用React Testing Library测试 Hooks(参见 packages/react/src/hooks 下的*.test.ts/*.test-d.ts文件),而 Testing Library 本身也支持 Svelte、Solid 等多个框架。

可借鉴的测试模式

  • 行为测试(.test.ts:渲染一个包着WagmiProvider的测试组件,断言 Hook 返回值随链切换、连接/断开账户而变化;仓库中的测试基建可参考 packages/react/test/setup.ts 与 packages/core/test/setup.ts。
  • 类型测试(.test-d.ts:用类型断言验证泛型推断是否正确,比如 useChainId.test-d.ts 这类文件,专门守护库的公共类型契约。

测试时重点关注:链切换后订阅是否触发、连接器变更后useConnection是否更新、组件卸载后订阅是否清理。这些行为正是响应式层正确性的直接证据。

代理导出:简化使用者的导入路径

Wagmi 会直接代理(re-export)Wagmi Core 与 Viem 的导出,让使用者可以从一个包名里拿到所有常用能力,避免从多个包手动拼装导入。这个行为非常值得你在自己的框架包里模仿。

从源码看,packages/react/src/exports 下的index.tsactions.tshooks.ts等文件集中完成 re-export;packages/core/src/exports 中也有actions.tsquery.tsinternal.ts等细分导出面(例如internal.ts导出ConfigParameterQueryParameter等供框架层使用的内部类型)。仓库中的 scripts/generateConnectorExports.ts 与 scripts/generateProxyPackages.ts 脚本,进一步说明 wagmi 是用脚本自动生成这些代理导出的,以保持各包导出面的同步与一致。

给框架作者的建议:为你的包设计好导出面划分(如indexactionshooks/composables/primitivesquery),把 Core 和 Viem 的常用符号一并代理出去,能显著降低使用者的学习与接入成本。

结语

把 Wagmi Core 接入新框架并不需要重写任何链上逻辑——Core 本身是框架无关的。你要做的,是用框架的依赖注入机制传递 Config,用watch*系列订阅 API 把状态变化接进框架的响应式系统,再通过'@wagmi/core/query'复用 TanStack Query 的缓存与去重能力,最后用 Testing Library 和代理导出把体验打磨完整。

仓库中 packages/react、packages/vue、packages/solid 三个官方框架包,就是最好的"参考答案":以 useConnection 为连接原语范本、useChainId 为订阅范本、useConnectorClient 为 TanStack Query 集成范本,你的框架适配工作就有了完整的实现蓝图。

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

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

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

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

立即咨询