我来详细介绍在 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();
// 包含所有当前路由的参数
}