This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
在 Expo Router 中在页面之间导航
编辑页面
了解在 Expo Router 中链接到页面和导航到页面的不同方式。
一旦你的应用中有了几个页面并完成了它们的布局设置,就该开始在它们之间进行导航了。Expo Router 中的每个页面默认都有一个 URL,因此你可以使用链接以及与 Web 上相同的 URL 模式在页面之间导航。
使用 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="前往 About" onPress={() => router.navigate('/about')} />; }
Expo Router 应用默认使用栈导航,其中导航到新路由会将一个屏幕压入栈中,而从该路由返回则会将其从栈中弹出。通常,你会希望使用 router.navigate 函数。它要么会将新页面压入栈中,要么会回退到栈中已存在的路由。不过,你也可以调用 router.push 来显式地将新页面压入栈中,调用 router.back 返回上一页,或者调用 router.replace 替换栈中的当前页面。
在 Expo Router 中,你可以通过页面的 URL,或者它们相对于 src/app 目录的位置来引用页面。看看下面的文件结构,以及你会如何导航到每个页面:
srcappindex.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">关于</Link> </View> ); }
默认情况下,Link 组件会将其子元素渲染在一个 <Text> 元素内。这意味着非文本子元素(例如 View)可能会出现意外的布局行为。若要完全控制布局,请将 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">前往文章</Link>
router.navigate('./article');
动态路由和 URL 参数

了解如何使路由的某个段成为动态的。
动态路由可以通过完整 URL 进行链接,或者通过传递一个 params 对象来链接。
请考虑以下文件结构:
srcappuser[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"> 查看用户(id 内联) </Link> <Link href={{ pathname: '/user/[id]', params: { id: 'bacon' } }} > 查看用户(id 作为 href 中 params 的值) </Link> <Pressable onPress={() => router.navigate({ pathname: '/user/[id]', params: { id: 'bacon' } }) } > <Text>查看用户(命令式)</Text> </Pressable> </View> ); }
某些参数保留供 Expo Router 和 React Navigation 内部使用。你可以在 使用 URL 参数指南 中找到它们。
传递查询参数
你可以在链接 URL 本身中指定查询参数,也可以在 params 对象中作为额外参数传入。任何与动态路由变量名称不匹配的参数都等同于查询参数。
<Link href="/users?limit=20">查看用户</Link> <Link href={{ pathname: '/users', params: { limit: 20 } }}> 查看用户 </Link>
在目标页面中使用动态路由变量和查询参数
链接 URL 中的所有变量都可以通过 useLocalSearchParams hook 被接收页面访问。这个 hook 会返回一个包含所有 URL 参数的对象,包括通过 params 传入的参数。
例如,如果你有如下链接:
<Link href="/users?limit=20">查看用户</Link>
那么你可以像这样在另一端读取这些参数:
import { useLocalSearchParams } from 'expo-router'; import { View, Text } from 'react-native'; export default function Users() { const { id, limit } = useLocalSearchParams(); return ( <View> <Text>用户 ID:{id}</Text> <Text>限制:{limit}</Text> </View> ); }
在不导航的情况下更新查询参数
查询参数可以在不导航到新页面的情况下更新。这可以通过使用与当前页面相同 URL 的 Link 但更新查询参数来实现,也可以通过命令式方式实现。
<Link href="/users?limit=50">查看更多用户</Link> <Pressable onPress={() => router.setParams({ limit: 50 })}> <Text>查看更多用户</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()更新选项 - 不能监听来自导航器的事件(例如 focus、tabPress 等)。
当你导航到该屏幕后,navigation 对象会更新。因此,如果你在 useEffect hook 中有一个事件监听器,并且依赖于 navigation,那么当屏幕被导航到时,它会添加任何监听器:
const navigation = useNavigation(); useEffect(() => { const unsubscribe = navigation.addListener('tabPress', () => { // 执行某些操作 }); return () => { unsubscribe(); }; }, [navigation]);
同样地,对于分发操作或更新选项,你可以在执行之前检查屏幕是否处于聚焦状态:
const navigation = useNavigation(); if (navigation.isFocused()) { navigation.setOptions({ title: '已更新标题' }); }
有关更多信息,请参阅 React Navigation 预加载文档。
深度链接
深度链接是指某个 URL 在你的应用中打开特定页面。Expo Router 默认支持深度链接,因此你可以像在应用内使用 Link 一样,从应用外部通过 URL 链接到应用中的任意页面。这对于分享应用中特定页面的链接尤其有用。
在 web 上,深度链接就像在浏览器中导航到该特定 URL 一样简单。在移动端,你需要在 应用配置 文件中定义一个 scheme,它将成为进入你应用的深度链接前缀。
假设你的 scheme 是 myapp,以下是一些如何从网页或另一个应用链接到你应用中页面的示例:
srcappabout.tsxmyapp://aboutprofileindex.tsxmyapp://profileusers[username].tsxmyapp://users/evanbacon通过 app links 和 universal links,你也可以使用 https URL 链接到你的应用。有关更多信息,请参阅 通用链接。
初始路由
当打开指向你应用中某个页面的深度链接时,你通常会希望返回导航的行为与用户从首页导航到该页面时一样。为此,你可以指定 initialRouteName 配置,它定义了某个布局中应在深度链接页面之前加载的页面。
考虑以下文件结构:
srcappindex.tsxstackindex.tsxsecond.tsx_layout.tsxstack 是一个栈导航器,而 /stack/index 始终是栈中的第一个路由。
为了确保 /stack/index 始终最先加载,即使用户深度链接到 /stack/second,你也可以在 src/app/stack/_layout.tsx 中设置 initialRouteName:
export const unstable_settings = { // 确保任何路由都可以链接回 `/` initialRouteName: 'index', };
默认情况下,initialRouteName 只在深度链接时被考虑,而不会在应用内部导航时生效。不过,你可以在 Link 上使用 withAnchor 属性,强制在直接导航到应用内另一个栈时先加载初始路由。
因此,如果 src/app/index.tsx 中包含一个指向 /stack/second 的链接,添加 withAnchor 属性可确保 /stack/index 先被加载,这样当用户从 /stack/second 按下返回按钮时,就会回到 /stack/index:
<Link href="/stack/second" withAnchor> 前往第二页 </Link>
如果你在测试深度链接时缺少返回按钮,这通常可以通过设置initialRouteName来修复。