Google一键登录正常但常规Google登录失效问题求助
问题分析与解决方案
你的问题核心是One Tap弹窗的关闭事件没被正确监听,再加上启用FedCM后,Google账号服务的事件回调逻辑有变化:
- 你之前把切换按钮显示的逻辑绑定在
renderButton的click_listener上,但这个回调只有点击Google官方渲染的按钮才会触发,和One Tap弹窗的关闭按钮完全无关。 - 启用
use_fedcm_for_prompt: true后,One Tap的关闭事件需要用cancel_callback来捕获,这是FedCM规范下的专用回调。
修改后的代码
import React, { useState, useRef, useEffect } from 'react'; import { jwtDecode } from 'jwt-decode'; import axios from 'axios'; import { FcGoogle } from 'react-icons/fc'; const GoogleOneTapLogin = ({ setNavigateHome }) => { const googleButton = useRef(null); const [displayType, setDisplayType] = useState('flex'); const [gBtnDisplay, setGBtnDisplay] = useState('none'); const handleResponse = async (response) => { const token = response.credential; const { sub: uid, email, name, picture: photoURL } = jwtDecode(token); const username = email.split('@')[0]; const config = { headers: { 'Content-type': 'application/json', }, }; try { const result = await axios.post( `${import.meta.env.VITE_APP_SERVER_URL}/api/user/googleSignUp`, { uid, email, name, photoURL, username, }, config ); const user = result.data.result; window.localStorage.setItem( 'sketchApp', JSON.stringify({ email: user.email, isSignedIn: true }) ); setNavigateHome(prev => !prev); } catch (error) { console.log(error); alert('Something went wrong, please try again later.'); } }; // 组件挂载时初始化Google账号服务,只执行一次 useEffect(() => { if (!window.google) return; window.google.accounts.id.initialize({ client_id: import.meta.env.VITE_GOOGLE_CLIENT_ID, use_fedcm_for_prompt: true, auto_select: true, cancel_on_tap_outside: false, callback: handleResponse, // 新增:监听One Tap弹窗关闭事件 cancel_callback: () => { console.log('One Tap弹窗已关闭'); setDisplayType('none'); setGBtnDisplay('flex'); }, prompt_parent_id: 'googleButtonId', itp_support: true, ux_mode: 'popup', }); // 预先渲染常规Google登录按钮(默认隐藏) window.google.accounts.id.renderButton(googleButton.current, { theme: 'outline', size: 'large', logo_alignment: 'left', locale: 'en_US', text: 'continue_with', width: 280, }); }, []); const handleGoogleLogIn = () => { try { // 只触发One Tap弹窗,不再重复初始化服务 window.google.accounts.id.prompt(); } catch (error) { console.log(error); alert('Log In Failed. Please try again'); // One Tap失败时直接切换到常规登录按钮 setDisplayType('none'); setGBtnDisplay('flex'); } }; return ( <React.Fragment> <button className="googleButton bg-green-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded flex justify-center items-center" style={{ display: displayType, width: 'fit-content', marginTop: '1rem', }} onClick={handleGoogleLogIn} > <FcGoogle className="mr-2 text-2xl" /> Login with Google </button> <div id="googleButtonId" style={{ display: gBtnDisplay }} ref={googleButton} ></div> </React.Fragment> ); }; export default GoogleOneTapLogin;
关键改动说明
- 新增
cancel_callback:在初始化配置里添加这个回调,专门监听One Tap弹窗的关闭操作(包括点击关闭按钮、点击弹窗外部),触发后自动切换显示常规Google登录按钮。 - 初始化逻辑移到useEffect:避免每次点击自定义按钮都重复初始化Google账号服务,减少冗余操作和潜在冲突。
- 简化
handleGoogleLogIn:现在只负责触发One Tap弹窗,初始化和常规按钮渲染都在组件挂载时完成。 - 修正
prompt_parent_id绑定:把该属性对应的DOM元素直接绑定到常规按钮的容器上,符合FedCM的DOM层级要求。
内容的提问来源于stack exchange,提问作者Manas Telavane
相关产品推荐
相关产品推荐

