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

Vite+React中正确加载Google登录脚本的方法咨询

Vite + React + TS 中Google登录按钮的实现问题

问题描述

使用Vite搭建React+TS应用,尝试添加Google登录按钮。按照官方指南在index.html中直接引入GSI脚本时按钮无法显示,代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <script src="https://accounts.google.com/gsi/client" async></script>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

改用useEffect动态加载脚本后按钮可以显示,但认为该方式不够规范,希望了解更标准的实现方式,以及直接在index.html加载脚本失败的原因。

原因分析:为何index.html直接加载脚本无效

Google GSI脚本加载完成后会立即扫描页面中的g_id_onload和g_id_signin元素,你的实现存在两个关键问题:

  • 脚本执行时机过早:async属性让脚本异步加载,大概率会在React完成组件挂载(即渲染出Google登录相关DOM元素)前执行完毕,此时脚本找不到目标元素,无法渲染按钮。
  • 脚本位置错误:脚本放在<div id="root">之前,React挂载组件是在后续的main.tsx执行阶段,脚本执行时目标DOM还未生成。

标准实现方式

1. 调整index.html脚本加载时机(最简单修复)

将GSI脚本移至React入口脚本之后,并使用defer属性确保脚本在DOM解析完成后执行,同时保证React已渲染出目标元素:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
    <!-- 移至React脚本后,用defer保证DOM就绪后执行 -->
    <script src="https://accounts.google.com/gsi/client" defer></script>
  </body>
</html>

登录组件无需修改脚本加载逻辑,直接保留Google的DOM元素即可(注意修正htpp拼写错误为http):

export default function SignInButton() {
  return (
    <div>
      <div
        id="g_id_onload"
        data-client_id="你的客户端ID"
        data-context="signin"
        data-ux_mode="popup"
        data-login_uri="http://localhost:5173"
        data-auto_prompt="false"
      ></div>

      <div
        className="g_id_signin"
        data-type="standard"
        data-shape="rectangular"
        data-theme="outline"
        data-text="signin_with"
        data-size="large"
        data-logo_alignment="left"
      ></div>
    </div>
  );
}

2. 使用官方React库(推荐)

Google提供了适配React生态的官方库@react-oauth/google,完全遵循组件化思想,无需手动处理脚本加载:

步骤1:安装依赖

npm install @react-oauth/google

步骤2:在入口文件初始化Provider

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { GoogleOAuthProvider } from '@react-oauth/google';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <GoogleOAuthProvider clientId="你的客户端ID">
      <App />
    </GoogleOAuthProvider>
  </React.StrictMode>,
);

步骤3:在组件中使用登录按钮

import { GoogleLogin } from '@react-oauth/google';

export default function SignInButton() {
  const handleSuccess = (response: any) => {
    // 处理登录成功逻辑,如获取ID Token
    console.log('登录成功:', response);
  };

  const handleError = () => {
    console.log('登录失败');
  };

  return (
    <GoogleLogin
      onSuccess={handleSuccess}
      onError={handleError}
      uxMode="popup"
      theme="outline"
      size="large"
      text="signin_with"
      shape="rectangular"
      logoAlignment="left"
    />
  );
}

3. 优化动态加载脚本的实现(自定义场景)

如果需要自定义脚本加载逻辑,可优化为只加载一次脚本,并在脚本加载完成后手动初始化按钮:

import { useEffect, useRef } from "react";

export default function SignInButton() {
  const isScriptLoaded = useRef(false);

  useEffect(() => {
    if (isScriptLoaded.current) return;

    const script = document.createElement("script");
    script.src = "https://accounts.google.com/gsi/client";
    script.async = true;
    
    script.onload = () => {
      // 脚本加载完成后手动初始化并渲染按钮
      window.google?.accounts.id.initialize({
        client_id: "你的客户端ID",
        callback: (response) => console.log('登录回调:', response),
      });
      
      window.google?.accounts.id.renderButton(
        document.getElementById("g_id_signin")!,
        {
          type: "standard",
          shape: "rectangular",
          theme: "outline",
          text: "signin_with",
          size: "large",
          logo_alignment: "left",
        }
      );
    };

    document.body.appendChild(script);
    isScriptLoaded.current = true;

    return () => {
      document.body.removeChild(script);
      isScriptLoaded.current = false;
    };
  }, []);

  return <div id="g_id_signin"></div>;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:41:03