Search code examples
reactjsoauthoauth-2.0react-hooksgoogle-api-js-client

Refactoring a class based component to hooks (gapi API)


I am trying to refactor a class based component to a functional, that uses hooks. Am stuck at the right use of useState in gapi when trying to get my login status.

Just to know, what I would like to get:

1) Get a reference to the "auth" object after it is initialized

2) Figure out, if I am currently signed in

3) Print my authentication status on the screen

A similar question was already asked here: LINK but unfortunately I miss to implement the answer into my case.

Here is the class component:

import React from "react";

class GoogleAuth extends React.Component {
    componentDidMount() {
        window.gapi.load("client: auth2", () => {
            window.gapi.client
                .init({
                    clientId: "myVerySecretAPI",
                    scope: "email"
                })
                .then(() => {
                    this.auth = window.gapi.auth2.getAuthInstance(); //this gets me acces to the auth object
                    this.setState({ isSignedIn: this.auth.isSignedIn.get() });
                });
        });
    }

    renderAuthButton() {
        if (this.state.isSignedIn === null) {
            return <div>I dont know if we are signed in</div>;
        } else if (this.state.isSignedIn) {
            return <div>I am signed in!</div>;
        } else {
            return <div>I am not signed in</div>;
        }
    }

    render() {
        return <div>{this.renderAuthButton()}</div>;
    }
}

export default GoogleAuth;

An here is my refactored code:

import React, { useEffect, useState } from "react";

const GoogleAuth = () => {
    const [ auth, setAuth ] = useState(null);

    useEffect(
        () => {
            window.gapi.load("client:auth2", () => {
                window.gapi.client
                    .init({
                        clientId: "834243588921-gob95b7q7n3eids3fm8du8oharkv5od0.apps.googleusercontent.com",
                        scope: "email"
                    })
                    .then(() => {
                        setAuth(window.gapi.auth2.getAuthInstance());
                        auth({ isSignedIn: setAuth.isSignedIn.get() }); // this is the line where I get an error (please see below)
                    });
            });
        },
        [ auth ]
    );

    const renderAuthButton = (isSignedIn) => {
        if (isSignedIn === null) {
            return <div>I dont know if we are signed in</div>;
        } else if (isSignedIn) {
            return <div>I am signed in!</div>;
        } else {
            return <div>I am not signed in</div>;
        }
    };

    return <div>{renderAuthButton()}</div>;
};

export default GoogleAuth;

I get an error in chrome, saying that:

Uncaught TypeError: Cannot read property 'get' of undefined at GoogleAuth.js:16

I know, that I am missing a small something to understand the use of hooks. Any help is welcome!


Solution

  • So you are basically saving a couple items. The first is the actual auth instance you get from window.gapi.auth2.getAuthInstance() and the second is the authenticated state, isSignedIn. In your code you setAuth with the instance, but then try to call the saved instance and pass it some new object with isSignedIn as the key and the state setter as the value. This won't work.

    You can first get the instance, and then use the instance to get the auth state from it to save into your state. You should also use an empty dependency array so the effect is run only once when GoogleAuth is mounted.

    Additionally, your renderAuthButton function is defined to take an isSignedIn parameter, but you don't pass it anything in the return. Since this is a functional component though you can simply omit the parameter and use the state value in scope.

    const GoogleAuth = () => {
      const [isSignedIn, setIsSignedIn ] = useState(null);
    
      useEffect(
        () => {
          window.gapi.load("client:auth2", () => {
            window.gapi.client
              .init({
                clientId: "834243588921-gob95b7q7n3eids3fm8du8oharkv5od0.apps.googleusercontent.com",
                 scope: "email"
              })
              .then(() => {
                const authInstance = window.gapi.auth2.getAuthInstance();
                setIsSignedIn(authInstance.isSignedIn.get());
              });
          });
        },
        []
      );
    
      const renderAuthButton = () => {
        if (isSignedIn === null) {
          return <div>I don't know if we are signed in</div>;
        } else if (isSignedIn) {
          return <div>I am signed in!</div>;
        } else {
          return <div>I am not signed in</div>;
        }
      };
    
      return <div>{renderAuthButton()}</div>;
    };