user10286245
user10286245

Reputation:

Undefined is not an object (evaluating '_this2.setState')

I'm new on react-native development and i try to add a login / register to my application, my login by email and by facebook is working fine (i'm in Firebase database, so it's ok). I want to show another view after the login of the user. Here is my firebaseconfig (imported in my login) :

    export async function loginUser(email, password) {
  try {
    firebase
      .auth()
      .signInWithEmailAndPassword(email, password)
      .then(response => {
        this.setState({ authentificated: true });
      });
  } catch (error) {
    console.log(error.toString);
  }
}

export async function facebookLogin() {
  Facebook.initializeAsync("928193664206969");
  const { type, token } = await Facebook.logInWithReadPermissionsAsync(
    "928193664206969",
    {
      permissions: ["public_profile"]
    }
  );

  if (type == "success") {
    const credential = firebase.auth.FacebookAuthProvider.credential(token);

    firebase
      .auth()
      .signInWithCredential(credential)
      .then(response => {
        this.setState({ authentificated: true });
      })
      .catch(error => {
        console.log(error);
      });
  }
}

Here is my Login page :

import React from "react";
import { View, Text } from "react-native";
import EmailLoging from "../components/EmailLoging";
import { Welcome } from "../pages/Welcome";

export default class Login extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      email: "",
      password: "",
      authentificated: false
    };
  }

  renderCurrentState() {
    if (this.state.authentificated) {
      return <Welcome />;
    } else {
      return <EmailLoging />;
    }
  }

  render() {
    return this.renderCurrentState();
  }
}

In the application, when i click on login with facebook, it's work, then i go back to the login screen with this error :

undefined is not an object (evaluating '_this2.setState')
- node_modules\@firebase\auth\dist\auth.js:16:1054 in cb.prototype.toString
- node_modules\@firebase\auth\dist\auth.js:19:232 in <anonymous>
- node_modules\@firebase\auth\dist\auth.js:19:167 in xb
- node_modules\@firebase\auth\dist\auth.js:19:0 in wb
- node_modules\@firebase\auth\dist\auth.js:13:280 in <anonymous>
- node_modules\promise\setimmediate\core.js:37:14 in tryCallOne
- node_modules\promise\setimmediate\core.js:123:25 in setImmediate$argument_0
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:146:14 in _callTimer
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:194:17 in _callImmediatesPass
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:458:30 in callImmediates
* [native code]:null in callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:407:6 in __callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:143:6 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:142:17 in __guard$argument_0
* [native code]:null in flushedQueue
* [native code]:null in invokeCallbackAndReturnFlushedQueue

I have done some search on Stackoverflow, and i found this : TypeError: undefined is not an object (evaluating 'this.setState') but i have only arrow function so it's not the problem..

Thank you

Update : Now i don't have the error, but the screen didn't change after the login, my code, login functions : (firebaseConfig.js)

export async function loginUser(email, password) {
  try {
    firebase.auth().signInWithEmailAndPassword(email, password);
  } catch (error) {
    console.log(error.toString);
  }
}

export async function facebookLogin() {
  Facebook.initializeAsync("928193664206969");
  const { type, token } = await Facebook.logInWithReadPermissionsAsync(
    "928193664206969",
    {
      permissions: ["public_profile"]
    }
  );

  if (type == "success") {
    const credential = firebase.auth.FacebookAuthProvider.credential(token);

    firebase
      .auth()
      .signInWithCredential(credential)
      .catch(error => {
        console.log(error);
      });
  }
}

Login.js :

import React from "react";
import { View, Text } from "react-native";
import Welcome from "../pages/Welcome";
import Home from "../pages/Home";

export default class Login extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      email: "",
      password: "",
      authentificated: false
    };

    this.renderCurrentState = this.renderCurrentState.bind(this);
  }

  renderCurrentState = () => {
    if (this.state.authentificated) {
      return <Home />;
    } else {
      return <Welcome />;
    }
  };

  render() {
    return this.renderCurrentState();
  }
}

Welcome.js :

import React from "react";
import { StyleSheet, Text, Image } from "react-native";
import { LinearGradient } from "expo-linear-gradient";

import logo from "../../assets/icon.png";
import { Button, Icon, Container } from "native-base";
import { Actions } from "react-native-router-flux";
import { facebookLogin } from "../components/firebaseConfig";

export default class Welcome extends React.Component {
  render() {
    return (
      <LinearGradient
        colors={["#004aaf", "#000"]}
        style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
      >
        <Container style={styles.backgroundImage}>
          <Image source={logo} style={styles.logo}></Image>
          <Text style={styles.loginText}>
            ─── Se connecter / S'inscrire avec ───
          </Text>
          <Button
            light
            full
            rounded
            style={{ padding: 10 }}
            onPress={() => Actions.login()}
          >
            <Icon type="FontAwesome" name="envelope" />
            <Text>Mon adresse email</Text>
          </Button>
          <Button
            full
            rounded
            style={{ padding: 10, marginTop: 20 }}
            onPress={() =>
              facebookLogin().then(() => {
                this.setState({ authentificated: true });
              })
            }
          >
            <Icon type="FontAwesome" name="facebook" />
            <Text style={{ color: "#fff" }}>Mon compte Facebook</Text>
          </Button>
        </Container>
      </LinearGradient>
    );
  }
}
const styles = StyleSheet.create({
  backgroundImage: {
    flex: 1,
    width: "100%",
    height: "100%",
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "transparent",
    padding: 25
  },
  logo: {
    width: 170,
    height: 130
  },
  loginText: {
    paddingTop: 50,
    paddingBottom: 50,
    color: "#fff"
  }
});

Upvotes: 0

Views: 1272

Answers (1)

Leonel Machava
Leonel Machava

Reputation: 1531

this.setState() should be called from inside the React component. You are wrongly calling it inside facebookLogin() and loginUser() functions.

You can fix it like this:

export async function loginUser(email, password) {
  try {
    return firebase
      .auth()
      .signInWithEmailAndPassword(email, password)
  } catch (error) {
    console.log(error.toString);
  }
}

then in your component, you call

  loginUser().then(() => {
    this.setState({ authentificated: true });
  });

But please make sure the method where you call, this is properly bound. The common practice is to define methods like this:

  renderCurrentState = () => {

  }

Otherwise you would have to do the binding in component's constructor:

 constructor(props) {
    super(props);

    // ...
    this.renderCurrentState = this.renderCurrentState.bind(this);
  }

What I have done is change loginUser() to return a promise. Then you use the function inside your component.

EDIT:

You can add a prop, eg. onLogin which you can use in Login component to update the authenticated state.

  renderCurrentState() {
    if (this.state.authentificated) {
      return <Welcome />;
    } else {
      return <EmailLoging onLogin={this.updateState} />;
    }
  }

  updateState = () => {
    this.setState({ authentificated: true });
    // possibly other code

  }

You should call onLogin on loginUser().then(() => { ... })

Upvotes: 1

Related Questions