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

React页面刷新后出现Google Auth相关错误求助

问题描述

在React页面实现基础Google身份认证功能时,页面刷新后频繁出现Cannot read properties of undefined (reading 'accounts')错误,但初始加载或多次刷新清空控制台后错误会暂时消失,之后又会重现。此前还遇到google is not defined错误,因此在App.js中定义了const google = window.google;,怀疑问题出在index.html的脚本上,想明确错误根源及当前使用的Google Auth脚本是否正确。

相关代码

index.html

<script src="https://accounts.google.com/gsi/client" async defer></script>

App.js

import './App.css';
import { useEffect, useState } from 'react';
import jwt_decode from "jwt-decode";

const google = window.google;


function App() {

  const [ user, setUser ] = useState({});

  function handleCallbackResponse(response) {
    console.log("Encoded JWT ID token: " + response.credential);
    var userObject = jwt_decode(response.credential);
    console.log(userObject);
    
    setUser(userObject);
    document.getElementById("signInDiv").hidden = true;
  }


  function handleSignOut(event) {
    setUser({});
    document.getElementById("signInDiv").hidden = false;
  }

  useEffect(() => {

    // google from script in index.html

    google.accounts.id.initialize({
      client_id: "xxx",
      callback: handleCallbackResponse
    });

    google.accounts.id.renderButton(
      document.getElementById("signInDiv"),
      { theme: "outline", size: "large" }
    );

    google.accounts.id.prompt();

  }, []);
  
  // If there is signed in user then show sign out button
  // If there is no user then show sign in button

  return (
    <div className="App">
      <div id="signInDiv"></div>
        { 
          Object.keys(user).length != 0 &&
          <button onClick={(e) => handleSignOut(e)}>Sign Out</button>
        }

        { user &&
          <div>
            <img src={user.picture} alt="" />
            <h3>{user.name}</h3>
          </div>
        }
    </div>
  );
}

export default App;
问题根源与解决方案

错误原因

  1. 脚本异步加载时序问题:index.html中的Google Auth脚本使用了async defer,会在后台异步加载,可能晚于React组件的useEffect钩子执行。而你在App.js顶部直接赋值const google = window.google;,此时脚本未加载完成的话,window.google就是undefined,后续useEffect中访问google.accounts必然报错。
  2. 变量缓存失效值:即使脚本最终加载完成,组件初始化时google变量已经被赋值为undefined,不会自动更新,所以后续即使脚本加载完毕,这个变量依然无效。

解决方法

方法一:等待脚本加载完成后执行初始化

修改useEffect逻辑,确保Google API可用后再执行初始化:

useEffect(() => {
  function initGoogleAuth() {
    // 检查Google API是否已加载
    if (window.google?.accounts?.id) {
      window.google.accounts.id.initialize({
        client_id: "xxx",
        callback: handleCallbackResponse
      });

      window.google.accounts.id.renderButton(
        document.getElementById("signInDiv"),
        { theme: "outline", size: "large" }
      );

      window.google.accounts.id.prompt();
    } else {
      // 延迟100ms重试,直到脚本加载完成
      setTimeout(initGoogleAuth, 100);
    }
  }

  initGoogleAuth();
}, []);

同时删除App.js顶部的const google = window.google;,直接使用window.google访问,避免变量缓存旧值。

方法二:组件内动态加载脚本

通过动态创建脚本标签的方式,确保脚本加载完成后再执行初始化,这种方式更灵活且不阻塞页面渲染:

useEffect(() => {
  const script = document.createElement('script');
  script.src = 'https://accounts.google.com/gsi/client';
  script.onload = () => {
    window.google.accounts.id.initialize({
      client_id: "xxx",
      callback: handleCallbackResponse
    });

    window.google.accounts.id.renderButton(
      document.getElementById("signInDiv"),
      { theme: "outline", size: "large" }
    );

    window.google.accounts.id.prompt();
  };
  document.body.appendChild(script);

  // 清理函数,防止重复加载脚本
  return () => document.body.removeChild(script);
}, []);

方法三:临时同步加载脚本(仅用于验证)

若要快速验证问题是否由加载时机导致,可暂时移除脚本的async defer属性,让脚本同步加载:

<script src="https://accounts.google.com/gsi/client"></script>

注意:此方式会阻塞页面渲染,影响性能,不建议在生产环境使用。

关于Google Auth脚本的正确性

你使用的https://accounts.google.com/gsi/client是Google Identity Services(GIS)的官方脚本,是当前推荐的Google身份认证集成方案,脚本本身没有问题,错误源于脚本加载时机与React组件生命周期的配合不当。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 21:55:33