2

I have a login function to that authenticates with Firebase and then should call a login function passed down from a parent as props. Here it is:

class HeaderParentComponent extends Component { 
    toggleSignupLayoverAction(event){
        this.props.toggleSignupLayover("true")
    }
    signIn(e){

        e.preventDefault();
        var email = $(".login-email").val();
        var password = $(".login-user-password").val();

        firebase.auth().signInWithEmailAndPassword(email, password).then(function(user) {  
            var user = firebase.auth().currentUser;
            this.props.logUserIn(user);
        }).catch(function(error) {
        // Handle Errors here.
            var errorCode = error.code;
            var errorMessage = error.message;
  // ...
        });

    }
    render() {
        return (
            <div className="header-inner">
                <span onClick={this.props.toggleMenuOut} className="menuToggle"></span>
                <a className="logo-a-tag" href="#">
                    <img height="25" src="../../images/logo.png" alt="my logo"/>
                </a>
                <form className="header-searchbox">
                    <input placeholder="Search Samples Here..." onChange={this.props.updateSearch} value={this.props.searchInputVal} type="text"></input>
                </form>
                <div className="header-acc"><a className={"login " + this.props.loggedInState} href="#">Login</a><a onClick={this.toggleSignupLayoverAction.bind(this)} className={"create " + this.props.loggedInState} href="#">Create Account</a>
                <div className={"logged-in-header " + this.props.loggedInState}>Hello {this.props.LoggedInUsername}</div>
                </div>
                <div className="login-popup-par">
                    <form>
                        <input placeholder="Email Address" className="login-email" type="text"></input>
                        <input placeholder="Password" className="login-user-password" type="password"></input>
                        <button onClick={this.signIn.bind(this)}>Login</button>
                    </form>
                </div>
            </div>
            )
        }
}

The props that has been passed down from the parent for the moment has a basic console.log of "logged in". It is passed down through the this.props.logUserIn(user); props. The issue is im trying to call this after authentication with Firebase has succeeded hence why I but it in a .then function after the .signInWithEmailAndPassword(email, password) It seems that I can't call this.props.logUserIn from inside the Auth function but I have no idea why. If I move the props function to outside the auth function it will call it no problem. Why can't I access the props from in there?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
red house 87
  • 1,837
  • 9
  • 50
  • 99

1 Answers1

1

This is because the this in the anonymous function in then(function) by default refers to the window object. You're effectively trying to do window.props.logUserIn(user) which is obviously not desired.

To combat this you may use ES6 arrow functions that do not bind this and refers to that of the enclosing context, the component. With arrow functions, this will not be window, but the component and will execute the method properly:

firebase.auth().signInWithEmailAndPassword(email, password).then((user) => {  
    var user = firebase.auth().currentUser;
    this.props.logUserIn(user);
}).catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
});

A pre-ES6 way to do this is to use Function.prototype.bind on regular functions to explicitly bind this context and other arguments to the function. Here's an example:

firebase.auth().signInWithEmailAndPassword(email, password).then(function(user) {  
    var user = firebase.auth().currentUser;
    this.props.logUserIn(user);
}.bind(this));
//...

This works because this outside the anonymous function is the component, and the context is passed to the function.


You need a constructorwhich is called on class instantiation, and is needed to use props. See here, use:

constructor(props) {
    super(props);

    /*this.state = { //for state if needed

    };*/
}  

//...

signIn(e) {
   //...
}
Community
  • 1
  • 1
Andrew Li
  • 55,805
  • 14
  • 125
  • 143