【问题标题】:Why do I lose access to a this.state variable in my .then() promise? [duplicate]为什么我无法访问我的 .then() 承诺中的 this.state 变量? [复制]
【发布时间】:2018-07-17 03:29:21
【问题描述】:

我正在尝试为带有 firebase 身份验证/数据库的 react-native 移动应用创建登录和注册流程。

我可以使用 Login.js 中预先存在的电子邮件/密码成功登录。

当我尝试在 SignUp.js 中创建新帐户时出现问题

用户已正确添加到 Firebase 身份验证,但我希望我的用户个人资料有更多信息。这就是为什么我将他们的姓名、电子邮件和其他信息写入数据库的原因,这些信息已从 Signup.js 第 33 行的代码中删除,并在第 52 行使用帮助函数。

我的错误是 undefined is not an object(evaluating this.state.email),来自 SignUp.js 中的第 33 行

这对我来说没有意义,因为我可以使用 this.state.email 在 SignUp.js 的第 27 行成功创建用户

this.state.email 是否超出范围?任何帮助是极大的赞赏。

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/>
        )}}

登录.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>
        );
    }
}

【问题讨论】:

  • 它是否与箭头功能一起使用? (即将function(user) 更改为user =&gt;)匿名函数有时会在作用域上做一些奇怪的事情。

标签: javascript firebase react-native firebase-authentication


【解决方案1】:

this 在不同的函数中改变含义。这基本上就是为什么对象方法在 Javascript 中起作用的原因,因为 this 总是引用包含它的类。当您在匿名函数中使用 this 时,就像您在 SignUp.js 文件中所做的那样,您使用的 this 与以前不同。

一个简单的解决方法是添加如下一行:

let self = this;

或者,如果你只需要状态:

let state = this.state;

之前 firebase.auth().onAuthStateChanged(function(user) { 位。然后在里面,你使用你创建的变量而不是this。


要尝试的另一件事是将您的匿名function 更改为箭头函数。箭头函数不会修改 this 变量。所以,像:

firebase.auth().onAuthStateChanged((user) => {

【讨论】:

  • 忽略之前的评论,你的“另一件事”工作得很好。再次感谢。
  • @DavidOwens 啊,对不起。如果您实际上需要原始 this 对象中的更多变量,最好使用第一个变体。然后this.state 将变为self.state 并且this.writeUserData 将变为self.writeUserData。或者把匿名函数改成箭头函数,这样比较简单。
  • 这是 React 和 React Native 中很常见的问题。你很快就会成为一个伟大的侦探。诀窍是当您看到有关 cannot ___ of undefined 的错误时,立即开始思考 this 可能指的是什么,而您希望它被定义。
  • @DavidOwens 是的!当您使用匿名function 时,其中的this 实际上指的是函数本身。默认的 Javascript 函数没有 state 变量。
  • 每天学习新东西!谢谢@AurelBílý
【解决方案2】:

尝试使用普通的 javascript 函数进行回调,而不是 ES6 粗箭头。 所以而不是 response => {...} 采用 function(response){...}

this article或许能帮助你更多地了解粗箭头函数的作用域。

【讨论】:

  • 箭头函数不改变this,不像常规函数。 OP 说错误显示在SignUp.js 的第 33 行,这意味着第 27 行,在箭头函数内,工作正常。您不是在解决问题,而是在引入另一个范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-27
  • 2019-03-11
  • 2022-01-08
  • 2017-02-02
  • 2019-11-08
  • 2018-09-04
相关资源
最近更新 更多