Why does the Sign In With Google button disappear after I render it the second time?

Viewed 1628

I am using the Sign In With Google button from Google Identity. I have put the HTML from this button documentation page into a React component. Looks like this:

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>
    </>
  );
}

On loading the page the first time the Google sign-in button appears correctly and I can log in. The sign-in button is then replaced by a log-out button. The problem is that when I click the log-out button which should render the Google sign-in button again, it doesn't reappear! Why is that?

I can add that refreshing the page after logging out brings back the Google button.

2 Answers

The reason it doesn't work is because the accompanying client library doesn't run again on later renders.

On page load the client library runs and injects an iframe where the HTML is. On later renders one can see in the DOM that this doesn't happen; the HTML is present but no iframe.

One solution is to never remove the HTML from DOM. Instead, apply the style display: none to the sign-in button when in need of hiding it.

As Stian says, the google script injects the google button once the app renders. The problem is that if you re-render the component where your button is located it will disappear because the google script was already executed, and won't be executed in future re-renders (it won't inject the google button again).

A different solution is to call window.google.accounts.id.renderButton inside an useEffect, that useEffect should be placed inside the component that is re-rendered. This will re-inject the google button each time the useEffect is called (comoponent is re-rendered).

The first argument the renderButton method receives should be a ref to a div, the google script will inject the sign-in button inside that div.

NOTE: Remember to first initialize the google script calling google.accounts.id.initialize

Here's the example:

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} />
);
Related