react-native中如何使用expo-touter

33 阅读2分钟

我来详细介绍在 React Native 中使用 Expo Router 的完整指南。

1. 安装与配置

创建新项目

# 创建新的 Expo 项目
npx create-expo-app my-app --template

# 选择模板时选择带导航的模板
# 或直接使用空白模板
npx create-expo-app my-app
cd my-app

# 安装 Expo Router
npx expo install expo-router expo-linking expo-constants expo-status-bar react-native-safe-area-context react-native-screens

配置 package.json

{
  "main": "expo-router/entry"
}

配置 app.json

// app.json
{
  "expo": {
    "scheme": "dw", // 配置一个scheme
    // 安装的时候 貌似会自动添加plugins 没有自动添加手动添加(第一次尝试不确定)
    "plugins": [
      "expo-router"
    ]
  }
}

2. 基本文件结构

Expo Router 使用基于文件的路由系统,类似于 Next.js:

app/
├── _layout.tsx          # 根布局
├── index.tsx           # 首页 (/)
├── user/
│   ├── _layout.tsx     # 用户相关页面的布局
│   ├── index.tsx       # /user
│   └── [id].tsx        # /user/:id
├── profile.tsx         # /profile
├── settings/
│   ├── index.tsx       # /settings
│   └── notifications.tsx # /settings/notifications
└── 404.tsx             # 404 页面

3. 路由类型

静态路由

// app/profile.tsx
import { View, Text } from 'react-native';

export default function ProfileScreen() {
  return (
    <View>
      <Text>个人资料页面</Text>
    </View>
  );
}

动态路由

// app/user/[id].tsx
import { View, Text } from 'react-native';
import { useLocalSearchParams } from 'expo-router';

export default function UserDetailScreen() {
  const { id } = useLocalSearchParams();
  
  return (
    <View>
      <Text>用户 ID: {id}</Text>
    </View>
  );
}

嵌套路由

// app/settings/_layout.tsx
import { Stack } from 'expo-router';

export default function SettingsLayout() {
  return (
    <Stack
      screenOptions={{
        headerShown: true,
        title: '设置'
      }}
    >
      <Stack.Screen name="index" />
      <Stack.Screen name="notifications" />
    </Stack>
  );
}

4. 导航组件

Stack 导航器

// app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen 
        name="index" 
        options={{ title: '首页' }}
      />
      <Stack.Screen 
        name="profile" 
        options={{ title: '个人资料' }}
      />
      <Stack.Screen 
        name="user/[id]" 
        options={{ title: '用户详情' }}
      />
    </Stack>
  );
}

Tabs 导航器

// app/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function RootLayout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#007AFF',
        headerShown: false,
      }}
    >
      <Tabs.Screen
        name="index"
        options={{
          title: '首页',
          tabBarIcon: ({ color, size }) => (
            <Ionicons name="home" size={size} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: '个人资料',
          tabBarIcon: ({ color, size }) => (
            <Ionicons name="person" size={size} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="settings"
        options={{
          title: '设置',
          tabBarIcon: ({ color, size }) => (
            <Ionicons name="settings" size={size} color={color} />
          ),
        }}
      />
    </Tabs>
  );
}

5. 导航方法

使用 Link 组件

import { Link } from 'expo-router';
import { View, Text } from 'react-native';

export default function HomeScreen() {
  return (
    <View>
      <Link href="/profile">
        <Text>跳转到个人资料</Text>
      </Link>
      
      <Link href="/user/123">
        <Text>查看用户 123</Text>
      </Link>
      
      <Link href={{ pathname: "/user/[id]", params: { id: "456" } }}>
        <Text>查看用户 456</Text>
      </Link>
    </View>
  );
}

使用 useRouter 钩子

import { useRouter } from 'expo-router';
import { Button } from 'react-native';

export default function ProfileScreen() {
  const router = useRouter();
  
  return (
    <>
      <Button 
        title="返回首页" 
        onPress={() => router.back()} 
      />
      
      <Button 
        title="跳转到设置" 
        onPress={() => router.push('/settings')} 
      />
      
      <Button 
        title="跳转到设置(navigate)" 
        onPress={() => router.navigate('/settings')} 
      />
      
      <Button 
        title="替换当前页面" 
        onPress={() => router.replace('/user/789')} 
      />
      
      <Button 
        title="返回两级" 
        onPress={() => router.back(2)} 
      />
    </>
  );
}

带参数导航

import { useRouter } from 'expo-router';

export default function HomeScreen() {
  const router = useRouter();
  
  const navigateWithParams = () => {
    router.push({
      pathname: '/user/[id]',
      params: { 
        id: '123',
        name: 'John',
        age: '25'
      }
    });
  };
  
  const navigateWithQuery = () => {
    router.push('/search?q=react&sort=date');
  };
}

6. 参数获取

useLocalSearchParams

// app/search.tsx
import { useLocalSearchParams } from 'expo-router';
import { Text } from 'react-native';

export default function SearchScreen() {
  const params = useLocalSearchParams();
  // 访问 /search?q=react&sort=date
  // params = { q: 'react', sort: 'date' }
  
  return <Text>搜索: {params.q}</Text>;
}

useGlobalSearchParams

// 在任何组件中获取全局参数
import { useGlobalSearchParams } from 'expo-router';

export default function AnyComponent() {
  const params = useGlobalSearchParams();
  // 包含所有当前路由的参数
}