6

I am trying to implement google sign-in in React. Here's my component -

import { Fragment, useEffect } from "react";
import { GOOGLE_CLIENT_ID } from "./some-file";

const GoogleSignIn = () => { 

  const googleSignInHandler = response => {
    console.log(response);
  }

  const initGsi = () => { 
    if(window.google) { 
        window.google.accounts.id.initialize({
            client_id: GOOGLE_CLIENT_ID,
            callback: googleSignInHandler
        });
    }
  }

  useEffect(() => {
   initGsi();
  }, []);

  return (
    <Fragment>
      <div
        id="g_id_onload"
        data-client_id={GOOGLE_CLIENT_ID}
        data-context="use"
        data-ux_mode="popup"
        data-auto_prompt="false"
      ></div>

      <div
        className={['g_id_signin', 'gsignin'].join(' ')}
        data-type="standard"
        data-shape="rectangular"
        data-theme="filled_blue"
        data-text="continue_with"
        data-callback={googleSignInHandler}
        data-size="large"
        data-logo_alignment="left"
      ></div>
    </Fragment>
  );
};

export default GoogleSignIn;
`

Apparently it works if I set data-auto_prompt="true" ie one-tap. But, I don't know how to make it work for the button click. I really don't want to use an npm package, besides they are also based on legacy Google sign-in. Is there a way?

  • Did you find the solution? – Tiisetso Tjabane Jul 18 '21 at 18:36
  • 1
    You cannot put a callback in a data-attribute and hope to get a valid function reference into the DOM. See this post about [how React treats attributes that end up in the DOM](https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html#changes-in-detail) scroll down to *Non-event attributes with function values*. – Martin Sep 06 '21 at 12:14

2 Answers2

2

I went through the same problem, when migrating from Google Sign-in to Google Identity Services.

You can only declare a global variable right below your imports and in the component assign a function to this global variable.

...
declare global {
  interface Window {
    handleCredentialResponse?: any;
  }
}

function App() {
  window.handleCredentialResponse = handleCredentialResponse;
...
<div
id="g_id_onload"
data-client_id="xxx"
data-context="use"
data-ux_mode="popup"
data-callback="handleCredentialResponse"
data-nonce=""
data-auto_prompt="false"></div>
Radek Mezuláník
  • 351
  • 1
  • 5
  • 15
1

I've spent my evening for finding workaround for google one tap and my approaches can be useful for you. The main problem: 'react is passing data-*** attributes as strings', thats why we are facing with these problems.

  1. The easiest way is create class component:

In the example below, I've created global function(customCallback) and bound it with callback(data-callback=customCallback), which google is waiting.

export class OneTapV2 extends React.Component {
  constructor(props) {
    super(props)
    window.customCallback = this.customCallback
  }

  customCallback(e) {
    console.log('ONE TAP version 2 ', e)
  }

  render() {
    return (
      <div
        id='g_id_onload'
        data-client_id='GOOGLE_ID'
        data-callback='customCallback'
      />
    )
  }
}
  1. This case for other people, who can't find normal way how to manage with oneTap OAuth. Guys please take a look on it https://developers.google.com/identity/gsi/web/guides/use-one-tap-js-api ; they describe how to open oneTap window by JS
Nikita
  • 21
  • 1
  • You are right. Just to be sure I dug up this post about [how React treats attributes that end up in the DOM](https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html#changes-in-detail) scroll down to *Non-event attributes with function values*. – Martin Sep 06 '21 at 12:16