【问题标题】:Why won't my container component receive result of Async Await properly?为什么我的容器组件不能正确接收 Async Await 的结果?
【发布时间】:2018-11-01 16:07:22
【问题描述】:

这让我有点发疯。

预期行为:

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

实际结果: 我单击按钮 > 它触发功能关闭 > 控制台日志以 undefined/false 出现 > 然后返回用户对象。

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

上下文:

我有一组 4 个实用函数。他们每个人都专注于 firebase/login 生命周期中的差异元素(注册、登录、注销、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

我在这里没有看到什么?

【问题讨论】:

  • “我在这里没有看到什么?” 在第一种情况下它的工作原理是使用await。在第二种情况下,您没有使用 await。然而,你混合async/await.then 回调的方式是相当不寻常的。你应该做try { return Boolean((await firebase.auth().signInWithEmailAndPassword()).user.email); } catch(e) { return false; }
  • 我建议 read up more on async/await 更好地了解它的实际工作原理。

标签: javascript reactjs firebase firebase-authentication


【解决方案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 的其他人有所帮助。这不是一个承诺,它是不可实现的。它必须接受回调。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-22
    • 1970-01-01
    相关资源
    最近更新 更多