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

React中Discord Activity加载时Setup函数执行两次致认证异常求助

Discord Activity Setup函数执行两次导致认证错误的解决方案

我希望Discord Activity加载时仅执行一次Setup函数,但代码中该函数执行了两次并引发错误(控制台错误截图:console errors)。其他功能正常,仅认证环节出现问题。

问题代码

function App() {
  const [auth, setAuth] = useState<authType>(null);

  async function setupDiscordSdk() {
    const CLIENT_ID = "my client id";
    const discordSdk = new DiscordSDK(CLIENT_ID, { disableConsoleLogOverride: true });
    await discordSdk.ready();
    console.warn('DISCORD SDK READY!') // 该日志打印两次

    // 向Discord客户端授权
    const { code } = await discordSdk.commands.authorize({
      client_id: CLIENT_ID,
      response_type: "code",
      state: "",
      prompt: "none",
      scope: [
        "identify",
      ],
    });

    // 从活动服务器获取access_token
    const response = await fetch("/api/token", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        code,
      }),
    });

    const { access_token, publicProfile, authkey } = await response.json();
    localStorage.setItem('bread:authkey', authkey);

    // 使用access_token向Discord客户端认证
    let auth = (await discordSdk.commands.authenticate({
      access_token,
    }) as authTypeNOTNULL);

    auth.publicProfile = publicProfile as boolean;
    auth.user.avatarURL = (auth.user.avatar ? `https://cdn.discordapp.com/avatars/${auth.user.id}/${auth.user.avatar}.png?size=256` : `https://cdn.discordapp.com/embed/avatars/${(BigInt(auth.user.id) >> 22n) % 6n}.png`);
    auth.discordSdk = discordSdk;
    setAuth(auth);
    console.warn('AUTHED SUCCESSFULLY.');
  };

  async function openLink(url: string) {
    console.warn('Trying to open URL', url);
    console.log(auth)
    if (!auth) return console.error('Not authed');
    return await auth.discordSdk.commands.openExternalLink({ url });
  };

  useEffect(() => console.log(auth), [auth]);

  useEffect(() => {
    setupDiscordSdk().catch(console.error);
  }, [])

  return (
    <>
      ...
    </>
  )
}

export default App;

解决方案

1. 理解触发原因

React 18+的开发模式下,StrictMode会强制重复执行空依赖的useEffect、组件构造函数等,用于检测潜在bug,生产环境不会有此行为。这是setupDiscordSdk执行两次的最常见原因。

2. 添加执行锁避免重复调用

使用useRef标记是否已执行过初始化,不会触发组件重渲染,是最简洁的方案:

function App() {
  const [auth, setAuth] = useState<authType>(null);
  const isSetupCompleted = useRef(false); // 新增ref标记

  async function setupDiscordSdk() {
    if (isSetupCompleted.current) return; // 已执行则直接返回
    isSetupCompleted.current = true; // 标记为已执行

    // 原有setup代码...
  };

  // 其他函数...

  useEffect(() => {
    setupDiscordSdk().catch(console.error);
  }, [])

  // ...
}

3. 临时关闭StrictMode(仅开发调试用)

找到项目入口文件(如index.tsx),移除<StrictMode>组件的包裹:

// 原代码
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

// 修改后
root.render(
  <App />
);

注意:此方案仅用于开发时验证问题,不建议长期关闭StrictMode,它能帮助提前发现很多潜在问题。

4. 检查组件挂载情况

确认App组件是否在应用中被多次渲染(比如路由配置错误、父组件重复渲染导致子组件重复挂载),确保组件仅挂载一次。

5. 生产环境验证

打包生产版本后,React StrictMode的双重执行逻辑会被移除,此时setupDiscordSdk会自然只执行一次,可以直接验证问题是否解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:04:57