Reputation:
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
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