0

I'm trying to build Google Authentication in React + Redux + Firebase. And I want to create user after google authentication. But this.props.createUser() is not working after Redirects on Firebase.

TypeError: Cannot read property 'props' of undefined

app/src/components/home.js

import React, { Component } from "react";
import { connect } from "react-redux";
import firebase from "../config/firebase";
import { createUser } from "../actions";

class Home extends Component {
  constructor(props) {
    super(props);

    this.state = {
      user: null
    };
  }

  async componentWillMount() {
    console.log("this", this.props);
    firebase.auth().onAuthStateChanged(user => {
      this.setState({ user });

      if (user) {
        this.props.history.push("/user/settings");
      }
    });

    firebase
      .auth()
      .getRedirectResult()
      .then(function(result) {
        if (result.credential) {
          var token = result.credential.accessToken;
          console.log("token", token);
        }
        var user = result.user;
        // Successfully got a user but type error in below
        this.props.createUser(user);
      })
      .catch(function(error) {
        console.log("error", error);
      });
  }

  onLogin = () => {
    const provider = new firebase.auth.GoogleAuthProvider();
    firebase.auth().signInWithRedirect(provider);
  };

  render() {
    return (
      <button className="btn btnPrimary" onClick={this.onLogin}>
        <span>Google Signin</span>
      </button>
    );
  }
}

function mapStateToProps({ user }) {
  return { user: user };
}

export default connect(mapStateToProps, { createUser })(Home);

app/src/actions/index.js

import firebase from "../config/firebase";

export function createUser(user) {
  console.log('user', user)
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
k10a
  • 947
  • 2
  • 11
  • 30

2 Answers2

1

Since you declare the callback with the function keyword, this inside the function refers to the function itself and not to the class on which you declared the componentWillMount method.

The simplest solution is to use fat arrow notation, as you do elsewhere already:

firebase
  .auth()
  .getRedirectResult()
  .then((result) => {
    if (result.credential) {
      var token = result.credential.accessToken;
      console.log("token", token);
    }
    var user = result.user;
    // Successfully got a user but type error in below
    this.props.createUser(user);
  })

Also see this answer on the cause of the problem, and other solutions: How to access the correct `this` inside a callback?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
0

You need to use an arrow function here:

firebase
  .auth()
  .getRedirectResult()
  .then(function(result) {
    if (result.credential) {
      var token = result.credential.accessToken;
      console.log("token", token);
    }
    var user = result.user;
    // Successfully got a user but type error in below
    this.props.createUser(user);
  })
  .catch(function(error) {
    console.log("error", error);
  });

should be:

firebase
  .auth()
  .getRedirectResult()
  .then((result) => {
    if (result.credential) {
      var token = result.credential.accessToken;
      console.log("token", token);
    }
    var user = result.user;
    // Successfully got a user but type error in below
    this.props.createUser(user);
  })
  .catch(function(error) {
    console.log("error", error);
  });

The function() {} keyword is eating your this value.

HPierce
  • 7,249
  • 7
  • 33
  • 49