0

I am a student learning React. I am trying to create a web app where a user must sign in with Google before viewing any of the content. I began with the code from the github-notetaker example and have edited Main.js. So far, I am writing the entire logic inside the init() method and setting loggedIn and email values in this.state.

import React from 'react';
import { RouteHandler } from 'react-router';
import Rebase from 're-base';

class Main extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      loggedIn: props.loggedIn,
      email: props.email
    };
  }

  authDataCallback(authData) {
    if (authData) {
      console.log('User is already logged in.');
      console.log(authData["google"]["email"]); // works as expected
      this.setState({
        loggedIn: true,
        email: authData["google"]["email"]
      });
      console.log(this.state.email); // does not work as expected
    } else {

      this.setState({
        loggedIn: false
      });
      console.log('Attempting to authenticate user account');
      this.ref.authWithOAuthPopup('google', function (error, authData) {
        if (error) {
          console.log('Login Failed!', error);
        } else {
          console.log('Authenticated successfully');
        }
      }, {
        scope: "email"
      });
    }
  }
  init(){
    console.log('Init called');
    this.ref = new Firebase('https://myapp.firebaseio.com/');
    this.ref.onAuth(this.authDataCallback.bind(this));
  }

  componentWillMount(){
      this.router = this.context.router;
  }
  componentDidMount(){
    this.init();
  }
  componentWillReceiveProps(){
    this.init();
  }
  render(){
    if (!this.state.loggedIn) {
      return (
        <div className="main-container">
          <div className="container">
            <h3>You are not authenticated. <a href="">Login</a></h3>
          </div>
        </div>
      )
    } else {
      return (
        <div className="main-container">
          <div className="container">
            <RouteHandler {...this.props}/>
          </div>
        </div>
      )
    }
  }
};
Main.propTypes = {
  loggedIn: React.PropTypes.bool,
  email: React.PropTypes.string
};
Main.defaultProps = {
  loggedIn: false,
  email: ''
}
Main.contextTypes = {
  router: React.PropTypes.func.isRequired
};
export default Main;

I am encountering an odd bug and believe that I am doing this the wrong way. When the user authenticates successfully, all of the information is saved and the user's email is written. Here's what the console log looks like: User is already logged in. [email protected] // corresponds to authData["google"]["email"] [email protected] // corresponds to this.state.email = CORRECT!!

However, when I refresh the page, the new print looks like this, and it appears that the email and object are still available to me but are not getting saved in this.state. User is already logged in. [email protected] // corresponds to authData["google"]["email"] null

I am currently learning React and so this may be a really simple error. Thank you so much for your time and help in advance. If you could point me in the right direction or let me a know a better way to do this, I'd really appreciate it. Thanks!

2 Answers 2

1

I believe I found the reason for my issue. When I call the following code in render()

<h1> {this.state.email} </h1>

It works just fine. Therefore, my conclusion is that console.log(this.state.email) is somehow run before this.setState() is fully completed.

Sign up to request clarification or add additional context in comments.

1 Comment

setState is asynchronous. So you're correct in that the log will run before setState is finished. You can actually pass a callback into setState to run the specified code when setState is finished. So I'd try that. this.setState({newState: 'thing'}, function(){console.log(this.state.email)})
0

You're writing the code wrong. var currentAuthData = this.ref.getAuth(); sends a request to fireBase to get the authentication, however the next line of code if (currentAuthData) { is run before fireBase can retrieve the correct information. You must use a callback function instead.

ref.onAuth(authDataCallback);

function authDataCallback(authData) {
  if (authData) {
    console.log('User is already logged in.');
  }
}

3 Comments

thanks for helping me fix this method. I've updated the format to what I think is your suggestion in my original question. However, it still does not work when I refresh the page. I think this has more to do with my constructor overriding the this.setState part
Using onAuth() is a good approach. But this.ref.getAuth() does not send a request to Firebase. It instead returns the current authentication state of the client. See the API docs for getAuth().
Yup. getAuth() is synchronous.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.