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

Expo+AWS Cognito环境下React Navigation基于用户认证状态的条件路由失效问题

解决Expo + AWS Cognito认证状态更新与路由自动切换问题

我来帮你搞定这个问题,你遇到的核心问题其实有两个:一是你的认证状态只在App挂载时检查一次,登出后不会主动重新校验;二是initialRouteName仅在导航容器初始化时生效,后续状态变化无法触发路由自动切换。下面是具体的修复方案:


1. 先修复AppContext的状态更新方法

你当前的AppContext.Provider里传递的setUserID是个无效的空函数,子组件根本没法正确更新用户状态!把它改成直接传递真实的setUserID:

// App.js里的Provider部分
<AppContext.Provider value={{ userID, setUserID }}>
  <AppNavigation/>
</AppContext.Provider>

2. 监听AWS Cognito的认证状态变化

AWS Amplify的AuthHub可以监听登录、登出等认证事件,这样不用等页面刷新,就能立刻触发状态更新。同时要给currentAuthenticatedUser加上错误捕获(未登录时这个方法会抛出异常):

// App.js的useEffect修改
const App = () => { 
  const [userID, setUserID] = useState(null); 
  useEffect(() => { 
    const fetchUser = async () => {
      try {
        const userInfo = await Auth.currentAuthenticatedUser({ bypassCache: true }); 
        const userData = await API.graphql(
          graphqlOperation(getUser, { id: userInfo.attributes.sub })
        );
        // 确保获取不到用户数据时也设为null
        setUserID(userData.data.getUser || null);
      } catch (error) {
        // 未登录时捕获异常,将状态设为null
        setUserID(null);
      }
    };

    // 初始化时检查用户状态
    fetchUser();

    // 监听认证事件(登录/登出)
    const authListener = AuthHub.listen('auth', async (data) => {
      switch(data.payload.event) {
        case 'signOut':
          setUserID(null);
          break;
        case 'signIn':
          await fetchUser();
          break;
      }
    });

    // 组件卸载时移除监听
    return () => authListener();
  }, []);

  // ... 其余代码不变
}

3. 放弃依赖initialRouteName,主动控制导航栈

initialRouteName只会在NavigationContainer第一次渲染时生效,后续状态变化不会自动切换路由。我们可以通过监听userID的变化,主动重置导航栈:

// AppNavigation.js修改
const AppNavigation = () => { 
  const { userID } = useContext(AppContext); 
  const navigation = useNavigation();

  useEffect(() => {
    // 当用户状态变化时,重置导航栈到对应页面
    if (userID === null) {
      navigation.reset({
        index: 0,
        routes: [{ name: 'SignIn' }],
      });
    } else {
      navigation.reset({
        index: 0,
        routes: [{ name: 'HomeDrawer' }],
      });
    }
  }, [userID, navigation]);

  return ( 
    <NavigationContainer> 
      <Drawer.Navigator 
        drawerContent={props => <DrawerContent {...props} />} 
        drawerPosition='left'
        // 移除initialRouteName,不再依赖它
      > 
        <Drawer.Screen name='HomeDrawer' component={MainNavStack} /> 
        <Drawer.Screen name='SignIn' component={SignIn} /> 
      </Drawer.Navigator> 
    </NavigationContainer> 
  )
}

4. 登出时的双重保险(可选)

虽然AuthHub已经能监听登出事件,但你可以在登出函数里主动触发状态更新,确保万无一失:

// 假设这是你的登出按钮回调
const handleSignOut = async () => {
  await Auth.signOut();
  const { setUserID } = useContext(AppContext);
  setUserID(null);
};

这样修改后,用户登出时AuthHub会立刻捕获事件并更新userID,AppNavigation里的useEffect会检测到状态变化,主动重置导航栈到登录页,完全不需要强制刷新就能生效。

内容的提问来源于stack exchange,提问作者igotbeatebydre

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:59:09