React Native+Firebase不同用户角色对应页面展示问题排查
问题:Expo + Firebase React Native应用角色页面渲染异常
使用Expo和Firebase开发React Native应用,包含体操运动员(Gymnast)和教练(Coach)两种角色,期望根据用户角色展示对应专属页面。用户数据存储在Firestore的users集合中,但当前代码无论登录角色是什么,都仅显示体操运动员页面,需排查错误并修正。
错误排查
- Firestore查询未执行:原代码仅创建了查询语句,未调用
.get()执行查询,也未获取结果判断角色。 - 逻辑分支无效:第二个
useEffect中else if (user)永远不会触发,第一个if (user)已覆盖所有用户存在的情况,直接设置gymnastLoggedIn = true,导致教练角色无法被识别。 - 重复监听Auth状态:两个
useEffect都监听onAuthStateChanged,逻辑冗余且易引发状态冲突。 - 状态依赖错误:第二个
useEffect依赖user状态,但该状态从未更新,导致无法正常触发。
修正后的代码
import { useState, useEffect } from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import Ionicons from '@expo/vector-icons/Ionicons'; import firebase from 'firebase/app'; import 'firebase/auth'; import 'firebase/firestore'; // 导入你的页面组件 import Login from './screens/Login'; import SignUp from './screens/SignUp'; import PageOne from './screens/PageOne'; import HomeGymnast from './screens/HomeGymnast'; import GoalsGymnast from './screens/GoalsGymnast'; import SkillsGymnast from './screens/SkillsGymnast'; import CompetitionGymnast from './screens/CompetitionGymnast'; import Profile from './screens/Profile'; import HomeCoach from './screens/HomeCoach'; import GymnastsCoach from './screens/GymnastsCoach'; import GroupsCoach from './screens/GroupsCoach'; import ProfileCoach from './screens/ProfileCoach'; const Stack = createStackNavigator(); const Tab = createBottomTabNavigator(); export default function App() { const [isLoggedIn, setIsLoggedIn] = useState(false); const [userRole, setUserRole] = useState(null); // 直接存储用户角色,简化状态管理 useEffect(() => { // 仅保留一个Auth状态监听,避免冗余 const unsubscribe = firebase.auth().onAuthStateChanged(async (authUser) => { if (authUser) { setIsLoggedIn(true); // 执行Firestore查询获取用户角色 try { const userDoc = await firebase.firestore() .collection("users") .doc(authUser.uid) // 假设用户文档ID与Auth的UID一致 .get(); if (userDoc.exists) { const userData = userDoc.data(); setUserRole(userData.role); } else { console.log("用户文档不存在"); setUserRole(null); } } catch (error) { console.error("获取用户角色失败:", error); setUserRole(null); } } else { setIsLoggedIn(false); setUserRole(null); } }); // 组件卸载时清理监听 return () => unsubscribe(); }, []); // 加载状态处理,避免页面闪烁 if (isLoggedIn && userRole === null) { return <Text>加载中...</Text>; // 可替换为自定义加载组件 } if (isLoggedIn) { if (userRole === "Gymnast") { return ( <NavigationContainer> <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { let iconName; if (route.name === "Home") { iconName = focused ? "ios-home" : "ios-home-outline"; } else if (route.name === "Goals") { iconName = focused ? "checkmark-circle" : "checkmark-circle-outline"; } else if (route.name === "Skills") { iconName = focused ? "flame" : "flame"; } else if (route.name === "Competition") { iconName = focused ? "folder" : "folder-open"; } else if (route.name === "Profile") { iconName = focused ? "person" : "person"; } return <Ionicons name={iconName} size={size} color={color} />; }, tabBarActiveTintColor: "#314466", tabBarInactiveTintColor: "#665c5a", })} > <Tab.Screen name="Home" component={HomeGymnast} options={{ headerShown: true }} /> <Tab.Screen name="Goals" component={GoalsGymnast} options={{ headerShown: false }} /> <Tab.Screen name="Skills" component={SkillsGymnast} options={{ headerShown: false }} /> <Tab.Screen name="Competition" component={CompetitionGymnast} options={{ headerShown: false }} /> <Tab.Screen name="Profile" component={Profile} options={{ headerShown: true }} /> </Tab.Navigator> </NavigationContainer> ); } else if (userRole === "Coach") { return ( <NavigationContainer> <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { let iconName; if (route.name === "HomeCoach") { iconName = focused ? "ios-home" : "ios-home-outline"; } else if (route.name === "GymnastsCoach") { iconName = focused ? "at" : "at"; } else if (route.name === "GroupsCoach") { iconName = focused ? "contacts" : "contacts"; } else if (route.name === "ProfileCoach") { iconName = focused ? "person" : "person"; } return <Ionicons name={iconName} size={size} color={color} />; }, tabBarActiveTintColor: "#314466", tabBarInactiveTintColor: "#665c5a", })} > <Tab.Screen name="HomeCoach" component={HomeCoach} options={{ headerShown: true }} /> <Tab.Screen name="GymnastsCoach" component={GymnastsCoach} options={{ headerShown: false }} /> <Tab.Screen name="GroupsCoach" component={GroupsCoach} options={{ headerShown: false }} /> <Tab.Screen name="ProfileCoach" component={ProfileCoach} options={{ headerShown: true }} /> </Tab.Navigator> </NavigationContainer> ); } } // 未登录状态 return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Login" component={Login} options={{ headerShown: false }} /> <Stack.Screen name="SignUp" component={SignUp} options={{ headerShown: false }} /> <Stack.Screen name="PageOne" component={PageOne} options={{ headerShown: false }} /> </Stack.Navigator> </NavigationContainer> ); }
补充建议
- 文档ID关联:确保Firestore中
users集合的文档ID与Firebase Auth的用户UID一致,直接通过authUser.uid查询比where查询更高效。 - 错误处理:添加try-catch处理Firestore查询错误,避免因网络或权限问题导致应用崩溃。
- 状态简化:用
userRole直接存储角色类型,替代原来的两个布尔状态,逻辑更清晰。
内容的提问来源于stack exchange,提问作者JosineD58
相关产品推荐
相关产品推荐

