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
相关产品推荐
相关产品推荐

