How to remove Google OAuth2 gapi event listener?

Viewed 444

I am really struggling to understand how to remove the google gapi event listener. Below bold is the full function in question.

window.gapi.auth2.getAuthInstance().isSignedIn.listen(onAuthChange);

I would like to use my cleanup function in a useEffect hook to remove the event listener but the actual code to do this... I assume is different from simple javascript "removeEventListener"? I cannot find anything in google documentation. My problem is I need to know when the auth status changes on other pages and that requires other functions to run upon the event triggering (auth status changing) -- but since the original keeps running, I end up having a bunch of unnecessary function calls. It gets worse as you sign in and out... as the event listeners cumulate.


import React, { useEffect, useContext, useState } from "react";
import history from "../history";
import { GeneralContext } from "../contexts/General";

const GoogleAuth = () => {
  const { state, setState } = useContext(GeneralContext);

  const onAuthChange = () => {
    const auth = window.gapi.auth2.getAuthInstance();
    setState({ authStatus: auth.isSignedIn.get() });

    if (auth.isSignedIn.get() === true) {
      const token = auth.currentUser.fe.qc.access_token;
      setState({ accessToken: token });
    }
  };

  // Check auth status on mount
  useEffect(() => {
    window.gapi.load("client:auth2", () => {
      window.gapi.client
        .init({
          clientId:
            "320808104510-qjdjiooodidc8jm1i000oteqc7h63029.apps.googleusercontent.com",
          scope: "https://www.googleapis.com/auth/books",
        })
        .then(() => {
          const auth = window.gapi.auth2.getAuthInstance();
          //setState({ authStatus: auth.isSignedIn.get() });
          console.log("Event listender mounted on Sign-in Page");
          auth.isSignedIn.listen(onAuthChange);
        });
    });
  }, []);

  const onClick = () => {
    console.log(state.authStatus);
    const auth = window.gapi.auth2.getAuthInstance();
    auth.signIn();
    //setState({ authStatus: auth.isSignedIn.get() });
  };

  // Proceed to next page if user Signs into Google
  const proceed = () => {
    //Verify sign in
    if (state.authStatus === true) {
      //console.log("I am signed in");
      history.push("/home");
    }
  };

  // Runs after state updates
  useEffect(() => {
    proceed();

    return () => {
      // console.log("GoogleAuth Unmounted");
      // const auth = window.gapi.auth2.getAuthInstance();
      // window.removeEventListener(onAuthChange(), auth.isSignedIn.listen()); <--This is my attempt to remove the event listender, but it didn't work! 
    };
  }, [state.authStatus]);

  return (
    <React.Fragment>
      <div to="/" className="login btn" onClick={onClick}>
        Sign in with Google
        <svg className="google__svg">
          <use xlinkHref="img/sprite.svg#icon-google"></use>
        </svg>
      </div>
    </React.Fragment>
  );
};

export default GoogleAuth;

1 Answers

I had the same problem, and could not find any documentation to guide me in the right direction. While the docs I did find and the typescript typings all suggest that auth.isSignedIn.listen() has no return value, inspecting the return value in a browser console reveals this isn't the case.

It returns an object, and that object has a remove() method on its prototype. Save the returned object when you add your listener, and call its remove method in your cleanup.

  useEffect(
      () => {
        let listenerContext;

        window.gapi.load('client:auth2', () => {
          window.gapi.client.init({
            clientId,
            discoveryDocs: [...DISCOVERY_DOCS],
            scope: SCOPES,
          }).then(() => {
            const auth = window.gapi.auth2.getAuthInstance();
            listenerContext = auth.isSignedIn.listen(onSigninChange);
            // ... etc
          });
        });

        return () => {
          listenerContext?.remove();
        };
      },
      [],
  );

Because I could not find any documentation, I can't claim this is a stable long term feature. At the very least, I hope it helps you get unblocked in your project.

Related