Vue中Wagmi Hook使用报错:vue-query组合式函数仅可在setup内使用
问题:Vue项目中使用Wagmi Hook触发MINT函数时出现多个错误
在Vue项目的Pagename.vue文件中,使用Wagmi的useAccount、useContractRead、useContractWrite等Hook时,点击MINT按钮触发mintNew函数,控制台连续出现三个错误:
- vue-query组合式函数(如useQuery)只能在setup函数或生效的作用域内使用;
- [Vue warn]: inject() can only be used inside setup() or functional components;
- [Vue warn]: Unhandled error during execution of native event handler
相关代码如下:
<template> <div> <button type="button" @click="count++">+</button> <input autocomplete="off" type="text" :value="count" disabled /> <button type="button" autocomplete="off" @click="count--">-</button> <button type="submit" autocomplete="off" @click="mintNew(count)">MINT</button> </div> </template> <script setup> const count = ref(0) defineExpose({ count }) import { useAccount, useContractWrite, useContractRead } from 'use-wagmi' import json from '~/artifacts/contracts/GenTest2.sol/GenTest2.json' const contract = json const config = useRuntimeConfig() const contractAdd = config.public.contract const { isConnected } = useAccount() const thePrice = () => { useContractRead({ address: contractAdd, functionName: "T2G_PRICE", onSuccess(data) { console.log('success', data) } }) } async function mintNew(mintCount) { const { data, write: T2GMint } = useContractWrite({ address: contractAdd, abi: contract.abi, functionName: "T2GMint" }); const ethToBeSent = thePrice() * mintCount if(!isConnected) { alert('Connect Wallet to Mint or Enter amount more than 0') } else { T2GMint({ args: mintCount, value: ethToBeSent}) } return data } </script>
错误原因及修复方案
核心问题
Wagmi的所有Hook(基于Vue Query实现)属于Vue组合式API范畴,必须在setup函数的顶层(或其他组合式函数的顶层)调用,不能嵌套在普通函数、事件处理函数内部。你的代码中useContractRead放在了thePrice函数里,useContractWrite放在了mintNew事件处理函数里,违反了这个规则,导致了上述错误。
具体修复步骤
将
useContractRead移到setup顶层,存储合约价格
用ref变量存储价格,在useContractRead的onSuccess回调中更新这个值:const price = ref(0) useContractRead({ address: contractAdd, functionName: "T2G_PRICE", onSuccess(data) { console.log('success', data) // 将BigNumber格式转换为可读数值(根据合约实际情况调整) price.value = data?.toNumber() || 0 } })将
useContractWrite移到setup顶层,获取写入函数
在setup顶层初始化合约写入Hook,得到write函数供后续调用:const { write: T2GMint, data: mintData } = useContractWrite({ address: contractAdd, abi: contract.abi, functionName: "T2GMint" })重构
mintNew函数,使用预先获取的价格和写入函数
不需要在函数内部再调用Hook,直接使用setup顶层定义的变量和函数:async function mintNew(mintCount) { if (!isConnected || mintCount <= 0) { alert('请连接钱包或输入大于0的数量') return } // 计算要发送的ETH金额(注意单位转换,合约如果用Wei的话需要处理) const ethToBeSent = price.value * mintCount // 调用写入函数 T2GMint({ args: [mintCount], value: ethToBeSent }) return mintData }
完整修复后的代码
<template> <div> <button type="button" @click="count++">+</button> <input autocomplete="off" type="text" :value="count" disabled /> <button type="button" autocomplete="off" @click="count--">-</button> <button type="submit" autocomplete="off" @click="mintNew(count)">MINT</button> </div> </template> <script setup> import { ref } from 'vue' import { useAccount, useContractWrite, useContractRead } from 'use-wagmi' import json from '~/artifacts/contracts/GenTest2.sol/GenTest2.json' const count = ref(0) const price = ref(0) defineExpose({ count }) const contract = json const config = useRuntimeConfig() const contractAdd = config.public.contract const { isConnected } = useAccount() // 顶层调用useContractRead获取价格 useContractRead({ address: contractAdd, functionName: "T2G_PRICE", onSuccess(data) { console.log('success', data) price.value = data?.toNumber() || 0 } }) // 顶层调用useContractWrite获取写入函数 const { write: T2GMint, data: mintData } = useContractWrite({ address: contractAdd, abi: contract.abi, functionName: "T2GMint" }) async function mintNew(mintCount) { if (!isConnected || mintCount <= 0) { alert('请连接钱包或输入大于0的数量') return } const ethToBeSent = price.value * mintCount T2GMint({ args: [mintCount], value: ethToBeSent }) return mintData } </script>
额外注意事项
- 合约返回的价格通常是
BigNumber类型,需要根据合约的单位(比如Wei)转换为对应的ETH数值,避免计算错误。 - 调用
T2GMint时,args需要是数组格式(即使只有一个参数),确保和合约函数的参数列表匹配。
内容的提问来源于stack exchange,提问作者Meltxx
相关产品推荐
相关产品推荐

