Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I lose access to a this.state variable in my .then() promise? [duplicate]

I am trying to create a login and signup process for a react-native mobile app with firebase authentication/database.

I can successfully login with pre existing email/passwords in Login.js.

My problem arises when I attempt to create a new account in SignUp.js

The user is added to firebase authentication correctly but I want my user profiles to have more information. This is why I am writing to the database with their name, email, and other information I have removed from the code on line 33 in Signup.js with the helper function at line 52.

My error is undefined is not an object(evaluating this.state.email), coming from line 33 in SignUp.js

This does not make sense to me as I can create the user successfully on line 27 of SignUp.js using this.state.email

Is this.state.email going out of scope? Any help is greatly appreciated.

App.js

import React from 'react';
import { StackNavigator } from 'react-navigation';
import * as firebase from 'firebase'; 
import Dashboard from './components/Dashboard';
import Login from './components/Login';
import SignUp from './components/SignUp';

const Application = StackNavigator({
    Login: { screen: Login},
    SignUp: { screen: SignUp},
    Dashboard: { screen: Dashboard },
});

export default class App extends React.Component {
    componentWillMount(){
        const firebaseConfig = {
            apiKey: 'MY KEY',
            authDomain: 'MY DOMAIN',
            databaseURL: 'MY DATABASE URL',
        }
        if (!firebase.apps.length) {
            firebase.initializeApp(firebaseConfig);
        }
    }
    render() {
        return (
            <Application/>
        )}}

Login.js

import React from 'react';
import { StyleSheet, Text, View, KeyboardAvoidingView, ImageBackground } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Button } from 'react-native-elements';
import { Input } from './Input';
import Dashboard from './Dashboard';
import * as firebase from 'firebase';

export default class Login extends React.Component {
    constructor(props){
        super(props)
        this.state = {
            email: '',
            password: '',
        }
    }

    loginUser = (email, password, navigate) => {
        try{
            firebase.auth().signInWithEmailAndPassword(email, password)
            .then(function(user){
                console.log(user);
                navigate('Dashboard', {email, password});
            })
        }
        catch (error){
            alert('No known user for that email and password combination')
            console.log(error.toString());
        }
    }

    static navigationOptions = { header: null }

    render() {
        const{ navigate } = this.props.navigation;
        return (
            <KeyboardAvoidingView
                behavior='padding'>
                <Input
                    placeholder = 'Email'
                    onChangeText = {email => this.setState({email})}
                    value = {this.state.email}/>
                <Input
                    placeholder = 'Password'
                    secureTextEntry
                    onChangeText = {password => this.setState({password})}
                    value = {this.state.password}/>
                <Button
                    title = 'Log in'
                    onPress = {() => this.loginUser(this.state.email, this.state.password, navigate)}/>
                <Button
                    title = 'Sign up'
                    onPress = {() => navigate('SignUp')}/>
            </KeyboardAvoidingView>
        );
    }
}

SignUp.js

import React from 'react';
import { StyleSheet, Text, View, KeyboardAvoidingView, ImageBackground } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Button } from 'react-native-elements';
import { Input } from './Input';
import Dashboard from './Dashboard';

import * as firebase from 'firebase';

export default class SignUp extends React.Component {

    constructor(props){
        super(props)
        this.state = {
            firstName: '',
            lastName: '',
            email: '',
            password: '',
            confirmPassword: '',
        }
    }

    signUpUser = () => {
        try{
            if(this.state.password === this.state.confirmPassword){
                console.log('CREATING USER...');
                firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then( response => {
                    console.log('SIGNING IN...');
                    firebase.auth().signInWithEmailAndPassword(this.state.email, this.state.password)
                    firebase.auth().onAuthStateChanged(function(user) {
                        if (user) {
                            console.log('WRITING TO DATABASE...');
                            this.writeUserData(user, this.state.email, this.state.firstName, this.state.lastName);
                        }
                        else {
                            alert('Something went wrong. Please try again.');
                            return;
                        }
                    });
                })
            }
            else{
                alert('Passwords do not match');
                return;
            }
        }
        catch(error){
            console.log(error.toString());
        }
    }

    writeUserData = (user, email, first, last) => {
        console.log('ADDING USER ' + user.uid)
        try{
            firebase.database().ref('users/' + user.uid).set({
                email: email,
                first: first,
                last: last,
            });
        }
        catch(error){
            console.log(error.toString());
        }
        console.log('WRITE COMPLETE')
        //navigate to dashboard
    }

    static navigationOptions = { header: null }

    render() {
        const{ navigate } = this.props.navigation;
        return (
            <KeyboardAvoidingView
                behavior='padding'>
                <Input
                   placeholder = 'First Name'
                   onChangeText = {firstName => this.setState({firstName})}
                   value = {this.state.firstName}/>
                <Input
                    placeholder = 'Last Name'
                    onChangeText = {lastName => this.setState({lastName})}
                    value = {this.state.lastName}/>
                <Input
                    placeholder = 'Email'
                    onChangeText = {email => this.setState({email})}
                    value = {this.state.email}/>
                <Input
                    placeholder = 'Password'
                    secureTextEntry
                    onChangeText = {password => this.setState({password})}
                    value = {this.state.password}/>
                <Input
                    placeholder = 'Confirm password'
                    secureTextEntry
                    onChangeText = {confirmPassword => this.setState({confirmPassword})}
                    value = {this.state.confirmPassword}/>

                <Button
                    title = 'Create Account'
                    onPress = {() => this.signUpUser()}/>
                <Text
                    activeOpacity={0.75}
                    onPress = {() => this.props.navigation.goBack()}>
                    Go back
                </Text>
            </KeyboardAvoidingView>
        );
    }
}
like image 388
David Owens Avatar asked Dec 13 '22 18:12

David Owens


1 Answers

this changes meaning when it is in a different function. This is basically why object methods work in Javascript, because this always refers to the class containing it. When you use this in an anonymous function, like you do in your SignUp.js file, you are not using the same this as before.

A simple workaround is to add a line like:

let self = this;

Or, if you only need the state:

let state = this.state;

Before the firebase.auth().onAuthStateChanged(function(user) { bit. Then inside, you use the variable you created instead of this.


Another thing to try is to change your anonymous function into an arrow function. Arrow functions do not modify the this variable. So, something like:

firebase.auth().onAuthStateChanged((user) => {
like image 92
Aurel Bílý Avatar answered Dec 17 '22 23:12

Aurel Bílý