The hard part of this is, the official Google sign-in is using a
If you use
create-react-app, it locates in
If you don’t have that
your-client-ID, open this page, and click that CONFIGURE A PROJECT button.
The idea is, you just render a plain
div, then after
componentDidMount, use the Google API to re-render this
div as a real follow-google-design button, even better, you can bind your React component method to its
More info about the
render API and the others can be found here.
Now you can control the sign-in behavior from your React code.
If you ever need to consume API under
<script> and mounting of your React application are totally happening in parallel, so when you consume the API, the google script may not even be loaded.
I first did something simple, I removed the
defer attribute from the
<script> tag. And add an
onload attribute to an initializing function.
It appears working at first, but when you refresh the page, it’s always going to throw an exception if you try to consume
gapi.auth2.blahblah, it seems the
<script> loading happens after mounting of your React app, even though we have removed its
defer attributes to make it blocking rendering.
That means we need to know the lifecycle of the loading
<script>in your React app in order to get things done
For instance, I want to use its
isSignedIn API for a simple local protected route, if the user is signed-in, let the user access the resource, otherwise, route the user to the login page.
Yes, it’s the same as before,
defer will be there, and we will be fine.
The idea here is:
- We use
setIntervalto verify whether the
<script>tag has been loaded or not
- if loaded, we then
- For a better UX, we will save the steps in global store (Redux/MobX), then we can display different UI according to the different status, don’t worry, it will be pretty fast most of the time, should take only less than 2 seconds.
- After initializing, we will
- And when the status is been marked as done, your
Reactapp can use the Google API without any problems, because all the preparation has been done.
Here in that
googleLoadTimer will continue to check if the
window.gapi is ready if it’s ready, that means
<script> has been loaded. And it will
clearInterval as a teardown as we mentioned before after finishing initializing the
authStore is a mobx store. Feel free to use a redux store here, you just need to
actions to a
reducer which will be used later to indicate the steps, and you only need one property in this reducer, you can refer to the following mobx store code. You just need to swap
authStore.setAuthLoadingStatus(LOADING_STATUS.INITIAL); with something like
dispatch(initialAction()) if you are using Redux.
LOADING_STATUS is an object for preventing relying on the string directly.
googleLoadTimer will be run when the app starts. And updates the
authStore.authLoadingStatus, in your code. You can now know if the preparation is done like this:
isReady equals true, that means you can start using it.
I encapsulate the logic into a top-level component,
ProtectedRoute, it’s a simple route for protecting routes from un-google-logged-in user. Which means, before it uses
GoogleUser.isSignedIn(), it will show the loading spinners according to the
authStore.authLoadingStatus, it will only invoke the
GoogleUser.isSignedIn() when the
isReady === true (Otherwise, you will get exception because
gapi.auth2 is not ready to use).
Hope it helps.