使用Expo Router时出现找不到导航上下文的问题求助
问题描述
基于Expo 52搭建的项目,使用Expo Router、自定义React Query客户端及路由守卫。原本运行正常,在开发引导页流程后,随机出现“找不到导航上下文”的错误,且该错误仅在从step1页面跳转至step2页面时触发。
项目文件夹结构
your-project/ ├── app/ │ ├── (auth)/ │ │ ├── onboarding/ │ │ │ ├── step1.tsx │ │ │ ├── step2.tsx │ │ ├── _layout.tsx │ ├── _layout.tsx ├── components/ │ ├── RouteGuard.tsx │ ├── CustomQueryClientProvider.tsx ├── package.json
错误日志
Error: Could not find a navigation context. Is your component inside a screen in a navigator? at useNavigation (useNavigation.tsx:16:11) at Step1 (step1.tsx:XX:XX) ...
相关代码
1. 路由守卫(RouteGuard.tsx)
import React from 'react'; import { useRouter, useSegments } from 'expo-router'; import { useQueryClient } from '@tanstack/react-query'; export default function RouteGuard({ children }: { children: React.ReactNode }) { const router = useRouter(); const segments = useSegments(); const queryClient = useQueryClient(); React.useEffect(() => { const isOnboardingCompleted = queryClient.getQueryData(['onboarding-status']); if (!isOnboardingCompleted && segments[0] !== '(auth)/onboarding/step1') { router.replace('/(auth)/onboarding/step1'); } }, [segments, queryClient, router]); return <>{children}</>; }
2. 自定义React Query Provider(CustomQueryClientProvider.tsx)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60000, }, }, }); export default function CustomQueryClientProvider({ children }: { children: React.ReactNode }) { return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>; }
3. App路由布局(app/_layout.tsx)
import { Stack } from 'expo-router'; import CustomQueryClientProvider from '../components/CustomQueryClientProvider'; import RouteGuard from '../components/RouteGuard'; export default function RootLayout() { return ( <CustomQueryClientProvider> <RouteGuard> <Stack> <Stack.Screen name="(auth)" options={{ headerShown: false }} /> </Stack> </RouteGuard> </CustomQueryClientProvider> ); }
4. Step1页面跳转逻辑(step1.tsx)
import { useRouter } from 'expo-router'; import { Button } from 'react-native'; export default function Step1() { const router = useRouter(); const handleNext = () => { router.push('/(auth)/onboarding/step2'); }; return <Button title="下一步" onPress={handleNext} />; }
解决方案
1. 调整路由守卫的嵌套顺序
Expo Router的导航上下文由Stack/Tabs等组件提供,当前布局中RouteGuard包裹了Stack,导致守卫内部无法获取导航上下文。修改布局,将路由守卫作为屏幕的子组件:
修改app/_layout.tsx:
import { Stack } from 'expo-router'; import CustomQueryClientProvider from '../components/CustomQueryClientProvider'; import RouteGuard from '../components/RouteGuard'; export default function RootLayout() { return ( <CustomQueryClientProvider> <Stack> <Stack.Screen name="(auth)" options={{ headerShown: false }} children={({ children }) => <RouteGuard>{children}</RouteGuard>} /> </Stack> </CustomQueryClientProvider> ); }
2. 确保状态更新完成后再跳转
随机错误可能源于React Query状态更新与路由跳转的时机冲突,在跳转前确保状态更新完成:
修改step1.tsx:
import { useRouter } from 'expo-router'; import { Button } from 'react-native'; import { useQueryClient } from '@tanstack/react-query'; export default function Step1() { const router = useRouter(); const queryClient = useQueryClient(); const handleNext = async () => { await queryClient.setQueryData(['onboarding-status'], true); router.push('/(auth)/onboarding/step2'); }; return <Button title="下一步" onPress={handleNext} />; }
3. 使用useFocusEffect替代普通useEffect
在路由守卫中,使用Expo Router提供的useFocusEffect监听路由变化,避免在上下文未就绪时触发逻辑:
修改RouteGuard.tsx:
import React from 'react'; import { useRouter, useSegments, useFocusEffect } from 'expo-router'; import { useQueryClient } from '@tanstack/react-query'; export default function RouteGuard({ children }: { children: React.ReactNode }) { const router = useRouter(); const segments = useSegments(); const queryClient = useQueryClient(); useFocusEffect( React.useCallback(() => { const isOnboardingCompleted = queryClient.getQueryData(['onboarding-status']); if (!isOnboardingCompleted && segments[0] !== '(auth)/onboarding/step1') { router.replace('/(auth)/onboarding/step1'); } }, [segments, queryClient, router]) ); return <>{children}</>; }
内容的提问来源于stack exchange,提问作者Ash Gharibyan
相关产品推荐
相关产品推荐

