为什么我的容器组件无法正确接收Async Await的结果?

时间:2018-11-01 16:07:22

标签: javascript reactjs firebase firebase-authentication

这让我有点发疯。

预期行为:

我单击一个按钮>触发checkLoginStatus>从firebase返回true或false>布尔值存储在isLoggedIn>中,即console.log'd

实际结果: 我单击按钮>它将关闭功能>控制台日志显示为undefined / false>然后返回用户对象。

问题: 为什么我的React容器方法isUserAlreadyAuthenticated()await完成之前退出了?

上下文:

我有一组4个实用程序功能。他们每个人都专注于firebase / login生命周期中的diff元素(注册,登录,注销,hasUserAuthenticatedBefore ...)

它们都是异步等待功能。因此,例如:这是登录名-可以正常工作:-

export const login = async (email, password) => {
    let defaultStatus = false;
    try {
        await firebase.auth().signInWithEmailAndPassword(email, password)
            .then(res => {
                // if firebase fires back a user object, then login is true.
                if (res.user.email) {
                    defaultStatus = true;
                }
            })
            .catch(error => {
                console.log('Firebase | sign in error: ', error.message);
                defaultStatus = false;
            });
    } catch (err) {
        console.log('Login | error: ', err);
    }
    console.log('login status after logging in Try/Catch is: ', defaultStatus);
    return defaultStatus;
}

注意:当我在容器中调用此函数时,它将获得正确的返回布尔响应。

现在...如果我看一下checkLoginStatus函数。任何变化或怪异而奇妙的重写都无法使其表现出类似的样式。

export const checkLoginStatus = async () => {
    let defaultStatus = false;
    try {
        firebase.auth().onAuthStateChanged(user => {
            // if user exists then defaultStatus = true;
            // if not exists then defaultStatus = false;
        })
    } catch (err) {
        console.log('sign up user error: ', err);
    }
    console.log('default status after checking login status: ', defaultStatus);
    return defaultStatus;
}

然后在我的容器中:-

isUserAlreadyAuthenticated = async () => {
    let isLoggedIn = await this.props.checkLoginStatus();
    console.log('is foo here? ===>', isLoggedIn); // undefined
}

我尝试过的事情:-

将util函数更改为Promise(这将得到checkLoginStatus并非函数错误)

从isUserAlreadyAuthenticated中删除异步;像正常函数一样触发它(因为异步部分是在util函数本身中管理的)。不高兴。

将onAuthStateChanged()api更改为.then()样式的承诺。没有变化。

我从checkLoginStatus中删除了所有Firebase代码,只是让它在setTimeout()之后返回了一个字符串-仍然在检索用户对象之前返回undefined

我在这里没看到什么?

1 个答案:

答案 0 :(得分:1)

感谢@FelixKling和@ Think-Twice。

我实际上确实结束了a)将util函数包装在Promise中,在异步等待时读取。以为我明白了,但是我没有一些怪癖。

关键似乎是放在递归元素中。

实用功能:

export function checkLoginStatus() {
    return new Promise((resolve, reject) => {
        const unsubscribe = firebase.auth().onAuthStateChanged(user => {
            unsubscribe(); // <--- calls itself and resolves with a successful user object or null
            resolve(user);
        }, reject('api has failed'));
    });
}

这会自我调用,直到用户响应是成功的用户对象或返回null为止。

然后在React端,我有一个Async-Await函数来等待诺言:

   isUserAlreadyAuthenticated = async () => {

        try {
            let user = await this.props.checkLoginStatus();
            console.log('react side: ', user);
            if (user && user.email) {
                this.setState({
                    isLoggedIn: true, // <-- when true page navs to Homepage
                });
            }
        } catch(err) {
            console.log('catch | api error: ', err);   
        }
    }

我希望这对围绕onAuthStateChanged() API进行操作的其他人有所帮助。这不是一个承诺,这是无法解决的。它必须进行回调。