Wagmi:切换连接钱包时如何重新获取合约数据?
Wagmi钱包切换时重新获取合约数据的正确方案
问题背景
需要在钱包账户切换时重新触发useContractReads获取最新的授权数据,避免前端缓存旧授权信息导致合约调用失败(区块链返回授权错误且MetaMask不弹出授权窗口)。现有账户切换检测代码能捕获地址变化,但手动调用refetch时抛出严格模式相关错误:
Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.invokeGetter
现有合约读取代码
const {address} = useAccount({ onConnect() { setUserAddress(address) } }) const {data: req, refetch} = useContractReads({ watch: true, contracts: [ { ...myContract, functionName: 'myValue1', }, { ...myContract, functionName: 'myValue2', }, { ...anotherContract, functionName: "allowance", args: [userAddress, myContractAddress], } ], onSuccess(req){ setMyValue1(req[0].result), setMyValue2(req[1].result), setAllowanceMyContract(req[2].result) } });
账户切换检测代码
const { connector: activeConnector } = useAccount(); useEffect(() => { const handleConnectorUpdate = ({ account, chain }: ConnectorData) => { if (account) { console.log("new account", account); } else if (chain) { console.log("new chain", chain); } }; if (activeConnector) { activeConnector.on("change", handleConnectorUpdate); } return () => activeConnector?.off("change", handleConnectorUpdate) as any; }, [activeConnector]);
正确实现方案
方案1:利用Wagmi自动触发机制(推荐)
Wagmi的useContractReads会根据依赖项自动更新查询,无需手动调用refetch,只需确保查询参数与当前账户地址同步:
- 修正账户地址同步逻辑,确保切换账户时
userAddress及时更新:
const { address: currentAddress } = useAccount({ onConnect({ address }) { setUserAddress(address); }, onDisconnect() { setUserAddress(undefined); }, }); // 监听地址变化,确保状态同步 useEffect(() => { setUserAddress(currentAddress); }, [currentAddress]);
- 修改
useContractReads配置,添加enabled并依赖userAddress,地址变化时自动重新查询:
const { data: req } = useContractReads({ enabled: !!userAddress, // 仅当存在有效地址时执行查询 watch: true, contracts: [ { ...myContract, functionName: 'myValue1', }, { ...myContract, functionName: 'myValue2', }, { ...anotherContract, functionName: "allowance", args: [userAddress, myContractAddress], } ], onSuccess(req){ setMyValue1(req[0].result); setMyValue2(req[1].result); setAllowanceMyContract(req[2].result); } });
方案2:修复手动调用refetch的问题
若需手动触发,需确保refetch是最新实例,且避免严格模式下的函数调用问题:
const { connector: activeConnector } = useAccount(); const { data: req, refetch } = useContractReads(/* 原有配置 */); useEffect(() => { const handleConnectorUpdate = async ({ account }) => { if (account) { // 等待地址状态更新完成后再执行查询 await new Promise(resolve => setTimeout(resolve, 100)); try { await refetch(); } catch (err) { console.error("重新查询合约数据失败:", err); } } }; if (activeConnector) { activeConnector.on("change", handleConnectorUpdate); } return () => { activeConnector?.off("change", handleConnectorUpdate); }; }, [activeConnector, refetch]); // 必须将refetch加入依赖数组,确保使用最新实例
关键注意事项
- 确保
userAddress与当前钱包地址严格同步,避免查询参数使用旧地址 useContractReads的enabled配置可精准控制查询触发时机,依赖项变化时自动执行- 手动调用
refetch时,必须将其加入useEffect依赖,避免闭包导致的旧函数实例调用问题
内容的提问来源于stack exchange,提问作者user130657
相关产品推荐
相关产品推荐

