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;
问题根源与解决方案
错误原因
- 脚本异步加载时序问题:index.html中的Google Auth脚本使用了
async defer,会在后台异步加载,可能晚于React组件的useEffect钩子执行。而你在App.js顶部直接赋值const google = window.google;,此时脚本未加载完成的话,window.google就是undefined,后续useEffect中访问google.accounts必然报错。 - 变量缓存失效值:即使脚本最终加载完成,组件初始化时
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
相关产品推荐
相关产品推荐

