如何阻止Firebase认证在then块Promise失败时仍设置登录用户
问题本质
signInWithCredential执行成功时,Firebase Auth就已经同步更新了全局登录状态,会立刻触发onAuthStateChanged回调把用户状态设为已登录,和后续的数据库操作结果无关,所以才会出现数据库写入失败仍跳转AppStack的问题。
解决方案
下面提供两种常用的实现方式:
方案1:新增校验状态,调整导航判断逻辑(更推荐)
不直接依赖Firebase的登录状态做导航判断,新增状态位标记用户是否完成了业务侧的校验(比如数据库写入成功),灵活度更高,方便后续扩展其他校验逻辑。
导航逻辑修改:
const [user, setUser] = useState(null); // 新增状态:标记用户是否通过业务侧校验 const [isValidated, setIsValidated] = useState(false); const onAuthStateChanged = (user: any) => { setUser(user); // 用户登出时同步重置校验状态 if (!user) setIsValidated(false); }; useEffect(() => { const subscriber = auth().onAuthStateChanged(onAuthStateChanged); return subscriber; }, []); // 导航判断同时满足「有登录用户」+「校验通过」 return ( <NavigationContainer theme={fxTheme}> {user && isValidated ? <AppStack /> : <AuthStack />} </NavigationContainer> );
第三方登录逻辑修改:
await auth() .signInWithCredential(facebookCredential) .then(async fUser => { try { const dbUser = await saveDb(fUser); // 数据库写入成功,标记校验通过 setIsValidated(true); } catch(e) { // 写入失败,清空Firebase登录状态+重置校验标记 await auth().signOut(); setIsValidated(false); // 可在这里添加登录失败的用户提示 } }) .catch(async error => { // 登录本身失败时也清空状态 await auth().signOut(); setIsValidated(false); });
方案2:数据库失败时主动登出(改动最小)
如果不想调整现有导航逻辑,可以在捕获到数据库写入错误时,主动调用Firebase的登出方法清空全局登录状态,onAuthStateChanged会自动把user设为null,就不会触发跳转了。
修改第三方登录逻辑即可:
await auth() .signInWithCredential(facebookCredential) .then(async fUser => { try { const dbUser = await saveDb(fUser); } catch(e) { // 写入失败直接登出,清空Firebase登录状态 await auth().signOut(); } }) .catch(error => { // 原有登录错误处理逻辑 });
注意事项
- 所有异步操作都要加
await,避免状态更新时序问题 - 建议在错误捕获分支添加用户可见的提示,避免用户无法感知登录失败的原因
内容的提问来源于stack exchange,提问作者Dinesh Kumar
相关产品推荐
相关产品推荐

