You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,只需确保查询参数与当前账户地址同步:

  1. 修正账户地址同步逻辑,确保切换账户时userAddress及时更新:
const { address: currentAddress } = useAccount({
  onConnect({ address }) {
    setUserAddress(address);
  },
  onDisconnect() {
    setUserAddress(undefined);
  },
});

// 监听地址变化,确保状态同步
useEffect(() => {
  setUserAddress(currentAddress);
}, [currentAddress]);
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:34:59