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

React页面刷新时useEffect异步函数未调用getSUserDetails问题

页面刷新时getSUserDetails未触发的排查与解决

核心排查方向

1. 本地缓存存在,直接跳过API分支

fetchWalletAddress逻辑优先读取localStorage中的SINGULARITY_ACCOUNT_DATA,如果刷新时该缓存未过期或未被清除,会直接返回缓存地址,不会进入调用getSUserDetails的分支。

验证方式:
打开浏览器控制台(F12)→ 切换到Application标签 → 找到Local Storage,检查是否存在SINGULARITY_ACCOUNT_DATA键。若存在,删除后刷新页面,观察getSUserDetails是否触发。

优化方案:
给缓存添加有效期判断,避免无效缓存一直生效:

export const fetchWalletAddress = async () => {
  const storedData = localStorage.getItem("SINGULARITY_ACCOUNT_DATA");
  if (storedData) {
    const parsedData = JSON.parse(storedData);
    const now = Date.now();
    // 设置1小时有效期,可根据需求调整
    if (parsedData.expireTime && now < parsedData.expireTime) {
      const addressFromStorage = parsedData?.gamePayWallet?.accounts.evmPublicAddress[0].publicAddress;
      return Promise.resolve(addressFromStorage);
    } else {
      // 缓存过期,删除后走API逻辑
      localStorage.removeItem("SINGULARITY_ACCOUNT_DATA");
    }
  }

  // 缓存不存在/过期,调用API获取数据
  return getSUserDetails()
    .then(async (data) => {
      console.log("User data", data);
      let addressToSet;
      if (data) {
        addressToSet = JSON.parse(data).wallet.accounts.evmPublicAddress[0].publicAddress;
      } else {
        const loginData = await handleWaitingEvent("login");
        addressToSet = loginData.wallet.accounts.evmPublicAddress[0].publicAddress;
      }
      // 存入带有效期的缓存
      localStorage.setItem("SINGULARITY_ACCOUNT_DATA", JSON.stringify({
        gamePayWallet: JSON.parse(data).wallet,
        expireTime: Date.now() + 3600 * 1000
      }));
      return addressToSet;
    })
    .catch((error) => {
      console.log("Error while fetching data from API", error);
      throw error;
    });
};

2. window.SEvent刷新后未就绪,导致getSUserDetails静默失败

页面刷新后,window.SEvent可能还未完成初始化,此时调用window.SEvent.getConnectUserInfo()会报错,但getSUserDetails的catch块仅打印日志,容易被忽略,误以为函数未被调用。

验证方式:
查看浏览器控制台是否存在Error User Details ->开头的错误日志。

优化方案:
等待SEvent初始化完成后再执行逻辑:

export const getSUserDetails = async () => {
  // 等待SEvent全局对象就绪
  if (!window.SEvent) {
    await new Promise(resolve => {
      // 轮询检查,每100ms一次
      const checkInterval = setInterval(() => {
        if (window.SEvent) {
          clearInterval(checkInterval);
          resolve();
        }
      }, 100);
    });
  }

  try {
    const user = await window.SEvent.getConnectUserInfo();
    return JSON.stringify(user.metaData);
  } catch (err) {
    console.error("Error User Details ->", err);
    throw err;
  }
};

如果SEvent提供了初始化完成的事件(如s-event-ready),也可以用事件监听替代轮询:

export const getSUserDetails = async () => {
  if (!window.SEvent) {
    await new Promise(resolve => {
      window.addEventListener('s-event-ready', () => resolve(), { once: true });
    });
  }
  // 后续逻辑不变
};

3. 补充:Promise嵌套逻辑优化

原代码中addressToSet在data为空时返回Promise嵌套,虽不影响函数调用,但可能导致后续处理异常,建议改为async/await写法(如上述优化方案中的代码)。

内容的提问来源于stack exchange,提问作者Jai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:58:28