Reputation: 176
I have been trying the whole day to get Google authentication to work with React, but after searching for hours trying everything i found i only get a buggy, sometimes-working, mess. Can anyone see what i am doing wrong? (This is for a school project so i'm learning!)
The project will be an online schedule creator.
My main Index.js has the following render-function:
function renderApp() {
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={Login}></Route>
<Route component={AuthUserContainer}>
<Route path="/auth" component={Layout}>
<IndexRoute component={Overview}></IndexRoute>
<Route path="schedule(/:scheduleid)" component={Schedule}></Route>
</Route>
</Route>
</Router>,
app);
}
The home-page is simply a login page, handled by the Login component which will redirect the user to /auth if the authentication is successful. Authentication is continually handled by AuthUserContainer everytime a protected route is accessed.
The Login component has the Google Sign In button, and all protected routes has (via Layout component) a Google Sign Out button.
My Header.js contains the "Google Sign Out button" (signOutHandler):
export default class Header extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.SignOutHandler = this.SignOutHandler.bind(this);
}
SignOutHandler() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
Authenticate.signOutUser();
});
}
render() {
return (
<div class="header-content">
<h2 class="header-title">Schedule</h2>
<h3 class="header-user-button">
<a href="/" onClick={this.SignOutHandler}>User First Name</a>
</h3>
</div>
);
}
}
I used Googles own example code and tried to tweak it for React. Problems i get with this code is "Uncaught TypeError: Cannot read property 'getAuthInstance' of undefined". Since i split the Sign In and Sign Out buttons to separate pages auth2 doesn't get initialised properly, but clicking the button twice can make it work. Trying to initialise it manually here often gives me the error that Gapi is undefined...
Finally the Login.js:
export default class Login extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onSignIn = this.onSignIn.bind(this);
this.renderGoogleLoginButton = this.renderGoogleLoginButton.bind(this);
}
renderGoogleLoginButton() {
console.log('rendering google signin button')
gapi.signin2.render('my-signin2', {
'scope': 'https://www.googleapis.com/auth/plus.login',
'width': 200,
'height': 50,
'longtitle': true,
'theme': 'light',
'onsuccess': this.onSignIn
});
gapi.load('auth2', function() {
gapi.auth2.init();
});
}
componentDidMount() {
window.addEventListener('google-loaded', this.renderGoogleLoginButton);
}
onSignIn(googleUser) {
Authenticate.signInUser(googleUser.getBasicProfile());
this.props.router.push("/auth");
}
render() {
return (
<div class="container">
<h2 class="form-signin-heading">
Sign-in with Google account required
</h2>
<div id="my-signin2"></div>
</div>
);
}
}
I based this code also on Googles own, but that didn't work at all (either the button didn't load, simply nothing showed, or it never called onSignIn). I also found and tried this, which made it kinda work (sometimes). I also tried to initialise auth2 in renderGoogleLoginButton(), but that only works sometimes aswell...
renderGoogleLoginButton() is called by the even-handler of a custom event (google-loaded) which fires when the Google API loads (exactly like in the link). Authenticate is my own class which bundles together my creation of token, getUserName functions etc.
I also get the following error from gapi: "Uncaught TypeError: Cannot read property 'style' of null", i think it tries to reference the Sign In/ Sign Out buttons but since they aren't loaded at the time they are null.
I cannot find any good solutions that doesn't result in glitches or bugs. Googles own code places everything in the same HTML-document, but since i want to split it up into components then it all breaks. Am i doing this completly wrong perhaps? I'm very new to React but hopefully it's understandable!
Sorry for the long post, thank you so much for your time, and if you have any questions just ask!
Upvotes: 4
Views: 20095
Reputation: 767
React google login components are available. Its work for me.
Upvotes: 2
Reputation: 176
I got it working except for some minor complaints from gapi: "Cannot read property 'style' of null", this apparently has to do with gapi not finding the sign in button or something like that. I detect no functional errors.
For future reference, this is what i did (a bit of a quickfix but atleast it's working now):
All routes now have one route container enclosing all routes. That way the container is always called before any route is accessed, and i can there handle all authentication and login.
In this container (called Base) is an event-listener listening for when gapi (the google platform script) finishes loading. When the event fires i store gapi, and inits and stores auth2 as state variabels in Base. They only load once and from then on they will be passed to all components that need them through props.
My Header.js now has both the Sign In and Sign Out buttons. One is hidden while the other is displayed based on if you're logged in or not.
onSignIn(googleUser) is called every re-render, because you re-render the Google Sign In button. Since this is meant to be "the user clicked and signed in so let's redirect"-style this means Header.js has to remember the login state. (Did it re-render or did the user actually log in?) onSignIn is called every render because of the 'onsuccess' data tag.
Since the event is async i force a re-render when the state has been updated with gapi and auth2.
Hope this helps some people!
Upvotes: 2