reactjs 为什么“使用Google登录”按钮在我第二次渲染后消失?

5jvtdoz2  于 2023-03-12  发布在  React
关注(0)|答案(4)|浏览(253)

我正在使用Google Identity中的Sign In With Google按钮。我已经将button documentation page中的HTML放入React组件中。如下所示:

export default function GoogleLoginButton() {

  return (
    <>
      <div
        id="g_id_onload"
        data-client_id="XXXXXX"
        data-auto_prompt="false"
      ></div>
      <div
        className="g_id_signin"
        data-type="standard"
        data-size="large"
        data-theme="outline"
        data-text="sign_in_with"
        data-shape="rectangular"
        data-logo_alignment="left"
      ></div>
    </>
  );
}

在加载页面时,Google登录按钮第一次正确出现,我可以登录。登录按钮随后被注销按钮取代。问题是,当我点击注销按钮时,它应该再次呈现Google登录按钮,但它没有再次出现!这是为什么?
我可以补充说,在注销后刷新页面会带回谷歌按钮。

zlhcx6iw

zlhcx6iw1#

正如Stian所说,google script在应用程序渲染后会注入google button,问题是如果你重新渲染按钮所在的组件,它会消失,因为google script已经被执行过了,而且在未来的重新渲染中也不会被执行(它不会再注入google button)。
另一种解决方案是在useEffect中调用window.google.accounts.id.renderButton,useEffect应该被放置在被重新渲染的组件中。这将在每次调用useEffect时重新注入google按钮(组件被重新渲染)。
renderButton方法接收到的第一个参数应该是一个div的ref,google脚本将在该div中注入登录按钮。
注意:记住首先初始化google脚本调用google.accounts.id.initialize
下面是一个例子:

const divRef = useRef(null);

useEffect(() => {
  if (divRef.current) {
    window.google.accounts.id.initialize({
      client_id: <YOUR_CLIENT_ID_GOES_HERE>,
      callback: (res, error) => {
        // This is the function that will be executed once the authentication with google is finished
      },
    });
    window.google.accounts.id.renderButton(divRef.current, {
      theme: 'filled_blue',
      size: 'medium',
      type: 'standard',
      text: 'continue_with',
    });
  }
}, [divRef.current]);

return (
  {/* Other stuff in your component... */}

  {/* Google sign in button -> */} <div ref={divRef} />
);
snz8szmq

snz8szmq2#

它不起作用的原因是因为附带的client library在以后的渲染中不会再次运行。
在页面加载时,客户端库运行并在HTML所在的位置注入一个iframe。在稍后的渲染中,可以在DOM中看到这并没有发生;HTML存在,但没有iframe。
一种解决方案是永远不要从DOM中删除HTML,而是在需要隐藏登录按钮时将样式display: none应用于它。

11dmarpk

11dmarpk3#

对于TypeScript,我稍微修改了Alex的答案。
首先,不要忘记将<script src="https://accounts.google.com/gsi/client" async defer></script>添加到react public 文件夹中的 index.html 页面。
创建一个google_sso.ts文件并使用以下代码:

import { useRef, useEffect } from 'react';
declare const google: any;

const GoogleSSO = () => {

    const g_sso = useRef(null);

    useEffect(() => {
        if (g_sso.current) {
            google.accounts.id.initialize({
                client_id: "xxxxxxxx-koik0niqorls18sc92nburjfgbe2p056.apps.googleusercontent.com",
                callback: (res: any, error: any) => {
                    // This is the function that will be executed once the authentication with google is finished
                },
            });
            google.accounts.id.renderButton(g_sso.current, {
                theme: 'outline',
                size: 'large',
                type: 'standard',
                text: 'signin_with',
                shape: 'rectangular',
                logo_alignment: 'left',
                width: '220',
            });
        }
    }, [g_sso.current]);

    return (<div ref={g_sso} />);
}

export default GoogleSSO

然后在任何需要按钮的地方,使用此按钮:

import  GoogleSSO from "../common/google_sso";

<GoogleSSO />
o8x7eapl

o8x7eapl4#

我找到了另一个解决这个问题的方法,即创建一个useEffect钩子,在组件每次呈现时将Google button <script>标记插入DOM,这样可以防止在离开页面并返回时按钮消失,完整的React组件如下所示:

const GoogleButton = () => {
  useEffect(() => {
    const script = document.createElement('script');

    script.src = 'https://accounts.google.com/gsi/client';
    script.async = true;
    script.defer = true;

    document.body.appendChild(script);

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

  return (
    <>
      <div
        id='g_id_onload'
        data-client_id='your-client-id'
      />
      <div
        className='g_id_signin'
        data-type='standard'
        data-size='large'
        data-theme='outline'
        data-text='sign_in_with'
        data-shape='rectangular'
        data-logo_alignment='center'
      />
    </>
  );
};

相关问题