React Native中Firestore文档校验导致路由跳转异常问题
问题排查:新用户登录后未正确跳转至完善资料页面
场景与问题
业务场景
用户登录后,系统需检查Firestore中是否存在与当前用户UID关联的文档:
- 若文档存在,跳转至
HomeScreen - 若文档不存在,跳转至
FinishProfileScreen完善资料
原实现代码
/**Library Imports */ import React, { useState, useEffect } from 'react'; import { StyleSheet, Text, View } from 'react-native' import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { StackActions } from '@react-navigation/native'; import firestore from '@react-native-firebase/firestore'; import AsyncStorage from '@react-native-async-storage/async-storage' import auth from '@react-native-firebase/auth'; /**Screen Imports */ import HomeScreen from '../Screens/HomeScreen'; import FinishProfileScreen from '../Screens/login/FinishProfileScreen' const Stack = createNativeStackNavigator(); const AppStack = () => { let curUser = auth().currentUser; let routeName; const userRef = firestore().collection('users'); async function docExists(docName, docId) { const docRef = firestore().collection(docName).doc(docId); let docSnapshot = await docRef.get(); if (docSnapshot.exists) { console.log("docExists True") routeName = "HomeScreen" return true; } else { console.log("docExists False") routeName = "FinishProfileScreen" return false; } } docExists("users", curUser.uid) console.log(routeName) return ( <Stack.Navigator initialRouteName={routeName}> <Stack.Screen name = "Home" component = {HomeScreen} /> <Stack.Screen name = "FinishProfileScreen" component = {FinishProfileScreen} /> </Stack.Navigator> ) } export default AppStack
异常现象
创建新用户时,控制台日志显示docExists False,但系统仍跳转到HomeScreen而非FinishProfileScreen,控制台输出如下:
LOG undefined LOG docExists False LOG undefined LOG docExists False LOG undefined LOG docExists False LOG undefined LOG docExists False LOG undefined LOG docExists False
异常原因分析
- 异步操作执行顺序问题:
docExists是异步函数,调用时未等待其执行完成就渲染了导航器。组件初始渲染时routeName为undefined,React Navigation会默认选择栈中第一个定义的屏幕(即HomeScreen)。控制台先打印undefined再打印docExists False,也证明了这一点——组件先完成渲染,异步查询后才给routeName赋值,但此时导航器已完成初始化。 - 未使用React状态管理:
routeName是普通变量,不是React状态。即使异步操作后修改了routeName,也不会触发组件重新渲染,导航器无法感知到路由变化。 initialRouteName仅初始化生效:导航器的initialRouteName仅在第一次创建时生效,后续修改变量值不会改变初始路由设置。
解决方法
通过React状态管理和useEffect钩子调整异步逻辑,确保导航器在查询完成后再初始化,同时添加加载状态提升用户体验。修改后的完整代码如下:
/**Library Imports */ import React, { useState, useEffect } from 'react'; import { StyleSheet, Text, View, ActivityIndicator } from 'react-native' import { createNativeStackNavigator } from '@react-navigation/native-stack'; import firestore from '@react-native-firebase/firestore'; import auth from '@react-native-firebase/auth'; /**Screen Imports */ import HomeScreen from '../Screens/HomeScreen'; import FinishProfileScreen from '../Screens/login/FinishProfileScreen' const Stack = createNativeStackNavigator(); const AppStack = () => { const [initialRoute, setInitialRoute] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const checkUserDoc = async () => { const curUser = auth().currentUser; if (!curUser) { // 可根据业务需求跳转至登录页 setLoading(false); return; } const docRef = firestore().collection('users').doc(curUser.uid); const docSnapshot = await docRef.get(); if (docSnapshot.exists) { console.log("docExists True") setInitialRoute("Home"); } else { console.log("docExists False") setInitialRoute("FinishProfileScreen"); } setLoading(false); }; checkUserDoc(); }, []); // 查询完成前显示加载状态 if (loading) { return ( <View style={styles.loadingContainer}> <ActivityIndicator size="large" /> </View> ); } // 处理用户未登录的边界情况 if (!initialRoute) { return <Text>请先登录</Text>; } return ( <Stack.Navigator initialRouteName={initialRoute}> <Stack.Screen name = "Home" component = {HomeScreen} /> <Stack.Screen name = "FinishProfileScreen" component = {FinishProfileScreen} /> </Stack.Navigator> ) } const styles = StyleSheet.create({ loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', } }); export default AppStack
关键改动说明
- 使用
useState定义initialRoute和loading状态,确保状态变化能触发组件重渲染 - 在
useEffect中执行异步查询,确保组件挂载后才进行Firestore操作 - 添加加载状态,避免查询完成前渲染导航器导致默认路由跳转
- 检查
curUser是否存在,处理用户未登录或auth状态未初始化的边界情况 - 导航器的
initialRouteName使用状态变量,确保查询完成后设置正确的初始路由
内容的提问来源于stack exchange,提问作者Matthew Niculae
相关产品推荐
相关产品推荐

