You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 04:01:09