在 Expo Router 中页面之间导航
编辑
了解在 Expo Router 中链接和导航到页面的不同方式。
一旦您在应用程序中设置了一些页面及其布局,就该开始在它们之间导航了。Expo Router 中的导航与 React Navigation 类似,但由于所有页面默认都具有 URL,我们可以创建链接并使用这些 URL 以熟悉的 Web 模式在我们的应用程序中移动。
使用 useRouter 的原生导航基础
与 React Navigation 一样,您可以从 onPress 处理程序中调用函数以导航到另一个页面。在 Expo Router 中,您可以使用 useRouter 钩子访问导航函数:
import { useRouter } from 'expo-router'; import { Button } from 'react-native'; export default function Home() { const router = useRouter(); return <Button title="Go to About" onPress={() => router.navigate('/about')} />; }
Expo Router 应用程序默认使用堆栈导航,当导航到新路线时,会将一个屏幕推入堆栈,并在退出该路线时将其从堆栈弹出。通常,您想使用 router.navigate 函数。这将把新页面推入堆栈或者退回到堆栈中的现有路线。不过,您也可以调用 router.push 明确地将新页面推入堆栈,使用 router.back 返回到前一个页面,或使用 router.replace 来替换堆栈中的当前页面。
在 Expo Router 中,您可以通过其 URL 或相对于 app 目录的位置来引用页面。查看以下文件结构以及您如何导航到每个页面:
appindex.tsxrouter.navigate("/")about.tsxrouter.navigate("/about")profileindex.tsxrouter.navigate("/profile")friends.tsxrouter.navigate("/profile/friends")学习如何使用所有可用于复杂导航的函数。
链接和按钮
在 Expo Router 中链接到页面的典型方式是像 Web 应用程序一样使用链接。Expo Router 有一个 Link 组件用于在页面之间导航,href 就是您在 router.navigate 中使用的相同路由:
import { View } from 'react-native'; import { Link } from 'expo-router'; export default function Page() { return ( <View> <Link href="/about">About</Link> </View> ); }
默认情况下,链接只能包裹 Text 组件。您可以在使用 asChild 属性的链接内使用 Pressable 或其他支持 onPress 和 onClick 属性的组件:
import { Pressable, Text } from 'react-native'; import { Link } from 'expo-router'; export default function Page() { return ( <Link href="/other" asChild> <Pressable> <Text>Home</Text> </Pressable> </Link> ); }
了解使用链接进行导航时可用的选项。
了解如何在使用 Expo Router 的 iOS 上为您的链接添加预览。
相对路由
您并不总是需要使用路由的绝对路径。使用以 ./(当前目录)或 ../(上级目录)开头的路径将相对于当前路由进行导航。
相对 URL 是带有 ./ 的 URL 前缀,例如 ./article或 ./article/。相对 URL 相对于当前渲染的屏幕解析。
<Link href="./article">Go to article</Link>
router.navigate('./article');
动态路由和 URL 参数

学习如何使路由的一个部分动态。
动态路由可以通过完整 URL 链接,或通过传递 params 对象。
考虑以下文件结构:
appuser[id].tsx每个链接都将导航到相同的页面:
import { Link, router } from 'expo-router'; import { View, Pressable, Text } from 'react-native'; export default function Page() { return ( <View> <Link href="/user/bacon"> View user (id inline) </Link> <Link href={{ pathname: '/user/[id]', params: { id: 'bacon' } }} > View user (id in params in href) </Link> <Pressable onPress={() => router.navigate({ pathname: '/user/[id]', params: { id: 'bacon' } }) } > <Text>View user (imperative)</Text> </Pressable> </View> ); }
一些参数保留供 Expo Router 和 React Navigation 内部使用。您可以在 使用 URL 参数指南 中找到它们。
传递查询参数
您可以在链接 URL 本身中指定查询参数,或作为 params 对象中的附加参数。任何与动态路由变量名称不匹配的参数都相当于查询参数。
<Link href="/users?limit=20">查看用户</Link> <Link href={{ pathname: '/users', params: { limit: 20 } }}> View users </Link>
在目标页面中使用动态路由变量和查询参数
链接 URL 中的所有变量都可以通过 useLocalSearchParams 钩子访问到接收页面。该钩子返回一个包含所有 URL 参数的对象,包括作为 params 传递的那些。
例如,如果您有这样的链接:
<Link href="/users?limit=20">View users</Link>
那么您可以在另一端这样读取参数:
import { useLocalSearchParams } from 'expo-router'; import { View, Text } from 'react-native'; export default function Users() { const { id, limit } = useLocalSearchParams(); return ( <View> <Text>User ID: {id}</Text> <Text>Limit: {limit}</Text> </View> ); }
无需导航即可更新查询参数
可以无需导航到新页面而更新查询参数。这可以通过使用与当前页面相同的 URL 的 Link 来实现,但更新了查询参数,或者以强制方式实现。
<Link href="/users?limit=50">View more users</Link> <Pressable onPress={() => router.setParams({ limit: 50 })}> <Text>View more users</Text> </Pressable>
深入了解如何在 Expo Router 中设置和使用 URL 参数。
重定向
您可以使用 Redirect 组件从页面或布局立即重定向到另一个路由。这就像 replace 强制性导航函数一样。重定向将导航到新路由,而不会渲染当前页面。
import { Redirect } from 'expo-router'; export default function Page() { return <Redirect href="/about" />; }
预取
<Link /> 组件上的 prefetch 属性在组件渲染时启用目标屏幕的预取。这通过提前准备屏幕来加快导航速度。
import { Link } from 'expo-router'; export default function Page() { return <Link href="/about" prefetch />; }
当设置了 prefetch 时,Expo Router 将尝试在屏幕外渲染目标屏幕。具体行为取决于使用的导航器类型:
- Expo Router 导航器:在屏幕外渲染目标屏幕以启用预加载。
- 自定义导航器:可能以不同方式实现预取或根本不支持它。
当屏幕在堆栈导航器中预加载时,它将有一些限制:
- 它不能使用强制性的
routerAPI。 - 它不能使用
useNavigation().setOptions()更新选项。 - 它不能监听来自导航器的事件(例如焦点、tabPress 等)。
在您导航到屏幕时,导航对象将被更新。因此,如果您在 useEffect 钩子中有事件监听器并依赖于导航,它将在导航到屏幕时添加任何监听器:
const navigation = useNavigation(); useEffect(() => { const unsubscribe = navigation.addListener('tabPress', () => { // 做点什么 }); return () => { unsubscribe(); }; }, [navigation]);
同样,对于调度动作或更新选项,您可以在执行操作之前检查屏幕是否聚焦:
const navigation = useNavigation(); if (navigation.isFocused()) { navigation.setOptions({ title: 'Updated title' }); }
有关更多信息,请参考 React Navigation 预加载文档
深度链接
深度链接是指通过 URL 打开应用程序中的特定页面。Expo Router 默认支持深度链接,因此您可以使用外部 URL 链接到应用程序中的任何页面,就像您在应用程序内部使用 Link 一样。这对于共享指向应用程序中特定页面的链接尤其有用。
在 Web 上,深度链接和在 Web 浏览器中导航到该特定 URL 一样简单。在移动设备上,您需要在 应用配置 文件中定义一个 scheme,该 scheme 成为深度链接进入您的应用程序的前缀。
假设您的 scheme 是 myapp,以下是一些示例,说明如何从网页或其他应用程序链接到您应用程序中的页面:
appabout.tsxmyapp://aboutprofileindex.tsxmyapp://profileusers[username].tsxmyapp://users/evanbacon使用应用链接和通用链接,您还可以使用 https URL 链接到您的应用程序。有关更多信息,请参见 通用链接。
初始路由
在打开深度链接到您应用程序中的页面时,您可能希望后退导航的表现与用户从您的主页导航到该页面时相同。要做到这一点,您可以指定一个 initialRouteName 配置,定义在深度链接页面之前应该加载的布局页面。
考虑以下文件结构:
appindex.tsxstackindex.tsxsecond.tsx_layout.tsxstack 是一个堆栈导航器,而 /stack/index 始终是堆栈中的第一个路由。
为确保即使用户深度链接到 /stack/second,/stack/index 也始终首先加载,您可以在 app/stack/_layout.tsx 中设置 initialRouteName:
export const unstable_settings = { // 确保任何路由都可以链接回 `/` initialRouteName: 'index', };
默认情况下,仅在深度链接时考虑 initialRouteName,而在应用程序内部导航时不考虑。不过,您可以在 Link 上使用 withAnchor 属性,以强制在直接导航到应用程序中的另一个堆栈时加载初始路由。
因此,如果 app/index.tsx 中包含一个指向 /stack/second 的链接,请添加 withAnchor 属性,以确保首先加载 /stack/index,这将导致用户在从 /stack/second 按下后退按钮时返回 /stack/index:
<Link href="/stack/second" withAnchor> Go to second </Link>
如果在测试深度链接时缺少后退按钮,通常可以通过设置initialRouteName来解决。