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

Expo Router V2模板项目添加路由认证的最佳实践

Expo Router 适配现有目录的认证路由最佳实践

核心思路

Expo Router 基于文件系统路由,无需手动创建 NavigationContainer,核心是通过根布局文件结合认证状态拦截实现路由切换,完全适配你现有根为Stack、(tabs)为Tab的目录结构,在根层做全局认证守卫,同时保留原有路由结构。

具体实现步骤

1. 调整目录结构

在现有项目根目录下新增认证路由组,结构如下:

app/
├── (auth)/          # 独立的认证路由组
│   ├── login.tsx
│   ├── signup.tsx
│   └── _layout.tsx  # 认证组的Stack布局
├── (tabs)/          # 原有Tab路由组
│   ├── _layout.tsx
│   ├── home.tsx
│   └── profile.tsx
├── _layout.tsx      # 根布局,全局认证守卫在这里实现
└── index.tsx        # 根入口,负责初始路由重定向

2. 配置根布局 _layout.tsx

根布局作为全局路由入口,监听认证状态并动态切换路由:

import { Stack, useRouter, useSegments } from 'expo-router';
import { useEffect } from 'react';
// 替换为你实际的全局认证状态获取方式(Context/状态管理库)
import { useAuth } from '../contexts/AuthContext';

export default function RootLayout() {
  const { isAuthenticated } = useAuth();
  const segments = useSegments();
  const router = useRouter();

  useEffect(() => {
    const inAuthGroup = segments[0] === '(auth)';

    if (isAuthenticated && inAuthGroup) {
      // 已登录但在认证路由,重定向到Tab首页
      router.replace('/(tabs)/home');
    } else if (!isAuthenticated && !inAuthGroup) {
      // 未登录且不在认证路由,重定向到登录页
      router.replace('/(auth)/login');
    }
  }, [isAuthenticated, segments]);

  // 根Stack包裹所有路由组,隐藏默认头部避免层级冲突
  return <Stack screenOptions={{ headerShown: false }} />;
}

3. 配置认证组布局 (auth)/_layout.tsx

给认证路由设置独立的Stack布局,自定义导航样式:

import { Stack } from 'expo-router';

export default function AuthLayout() {
  return (
    <Stack>
      <Stack.Screen name="login" options={{ title: '登录' }} />
      <Stack.Screen name="signup" options={{ title: '注册' }} />
    </Stack>
  );
}

4. 保留原有Tab布局 (tabs)/_layout.tsx

无需修改原有Tab结构,保持你之前的配置即可,示例:

import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen
        name="home"
        options={{
          title: '首页',
          tabBarIcon: ({ color }) => <Ionicons name="home" color={color} size={24} />,
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: '我的',
          tabBarIcon: ({ color }) => <Ionicons name="person" color={color} size={24} />,
        }}
      />
    </Tabs>
  );
}

5. 根入口 index.tsx 初始重定向

避免初始空白页,根据认证状态直接跳转:

import { Redirect } from 'expo-router';
import { useAuth } from '../contexts/AuthContext';

export default function Index() {
  const { isAuthenticated } = useAuth();
  return isAuthenticated ? <Redirect href="/(tabs)/home" /> : <Redirect href="/(auth)/login" />;
}

关键注意事项

  • 禁止手动创建 NavigationContainer:Expo Router 会自动在根布局层生成,手动添加会导致路由冲突。
  • 实时认证状态:确保isAuthenticated状态是全局可访问且实时更新的,推荐用React Context或Zustand/Jotai等轻量状态管理库。
  • 路由组隔离:用括号包裹的路由组((auth)、(tabs))会被Expo Router识别为独立路由栈,避免嵌套导航冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:12:23