使用 URL 参数

编辑页面

了解如何在你的应用中访问和修改路由参数和搜索参数。


For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.

URL 参数包括 路由参数搜索参数。Expo Router 提供了用于访问和修改这些参数的 hooks。

路由参数和搜索参数的区别

路由参数是 URL 路径中定义的动态段,例如 /profile/[user],其中 user 是一个路由参数。它们用于匹配路由。

搜索参数(也称为 query params)是可序列化的字段,可以附加到 URL 上,例如 /profile?extra=info,其中 extra 是一个搜索参数。它们通常用于在页面之间传递数据。

本地与全局 URL 参数

在具有嵌套导航器的应用中,你通常会发现同一时间有 多个页面被挂载。例如,当一个新路由被压入栈时,栈会将上一页和当前页保留在内存中。正因为如此,Expo Router 提供了两个不同的 hooks 来访问 URL 参数:

  • useLocalSearchParams:返回当前组件的 URL 参数。它只会在全局 URL 与路由一致时更新。
  • useGlobalSearchParams:无论组件如何,都会返回全局 URL。它会在每次 URL 参数变化时更新,并且可能导致组件在后台发生额外更新。

useGlobalSearchParamsuseLocalSearchParams 这两个 hooks 允许你在组件中访问这些参数,从而获取并使用这两类 URL 参数。

这两个 hooks 的类型定义和使用方式相同。唯一的区别在于它们的更新频率。

下面的示例演示了 useLocalSearchParamsuseGlobalSearchParams 的区别。它使用如下 app 目录结构:

src
app
  _layout.tsx
  index.tsx
  [user].tsx

1

Root Layout 是一个栈导航器:

src/app/_layout.tsx
import { Stack } from 'expo-router'; export default function Layout() { return <Stack />; }

2

初始路由会重定向到动态路由 src/app/[user].tsx,并带有 user=evanbacon

src/app/index.tsx
import { Redirect } from 'expo-router'; export default function Route() { return <Redirect href="/evanbacon" />; }

3

动态路由 src/app/[user] 会打印全局和本地 URL 参数(在这里指路由参数)。它还允许通过不同的 路由参数 来推入同一路由的新实例:

src/app/[user].tsx
import { Text, View } from 'react-native'; import { useLocalSearchParams, useGlobalSearchParams, Link } from 'expo-router'; const friends = ['charlie', 'james'] export default function Route() { const glob = useGlobalSearchParams(); const local = useLocalSearchParams(); console.log("Local:", local.user, "Global:", glob.user); return ( <View> <Text>User: {local.user}</Text> {friends.map(friend => ( <Link key={friend} href={`/${friend}`}> 访问 {friend} </Link> ))} </View> ); }

4

应用启动时,会打印以下日志:

Terminal
Local: evanbacon Global: evanbacon

按下 "Visit charlie" 会将 /[user] 的一个新实例压入栈中,且 user=charlie,并记录以下日志:

Terminal
# 这条日志来自新屏幕Local: charlie Global: charlie# 这条日志来自第一个屏幕Local: evanbacon Global: charlie

按下 "Visit james" 也会产生类似效果:

Terminal
# 这条日志来自新的 "/james" 屏幕Local: james Global: james# 这条日志来自 "/evanbacon" 屏幕Local: evanbacon Global: james# 这条日志来自 "/charlie" 屏幕Local: charlie Global: james

结果:

  • 当 URL 路由参数 变化时,useGlobalSearchParams 会让后台屏幕重新渲染。如果过度使用,可能会导致性能问题。
  • 全局重新渲染会按栈顺序执行,因此第一个屏幕会先重新渲染,然后才是 user=charlie 屏幕重新渲染。
  • 即使全局 URL 路由参数 变化了,useLocalSearchParams 仍保持不变。你可以利用这一行为进行数据获取,以确保当你返回时,上一屏的数据仍然可用。

静态类型化的 URL 参数

useLocalSearchParamsuseGlobalSearchParams 都可以通过泛型进行静态类型化。下面是 user 路由参数的示例:

src/app/[user].tsx
import { Text } from 'react-native'; import { useLocalSearchParams } from 'expo-router'; export default function Route() { const { user } = useLocalSearchParams<{ user: string }>(); return <Text>User: {user}</Text>; } // 给定 URL:`/evanbacon` // 返回值如下:{ user: "evanbacon" }

任何搜索参数(例如 ?query=...)都可以选择性地添加类型:

src/app/[user].tsx
const { user, query } = useLocalSearchParams<{ user: string; query?: string }>(); // 给定 URL:`/evanbacon?query=hello` // 返回值如下:{ user: "evanbacon", query: "hello" }

当与 rest 语法(...)一起使用时,路由参数会以字符串数组返回:

src/app/[...everything].tsx
import { Text } from 'react-native'; import { useLocalSearchParams } from 'expo-router'; export default function Route() { const { everything } = useLocalSearchParams<{ everything: string[]; }>(); const user = everything[0]; return <Text>User: {user}</Text>; } // 给定 URL:`/evanbacon/123` // 返回值如下:{ everything: ["evanbacon", "123"] }

任何搜索参数将继续作为单独的字符串返回:

src/app/[...everything].tsx
import { Text } from 'react-native'; import { useLocalSearchParams } from 'expo-router'; export default function Route() { const { everything } = useLocalSearchParams<{ everything: string[]; query?: string; query2?: string; }>(); const user = everything[0]; return <Text>用户:{user}</Text>; } // 给定 URL:`/evanbacon/123?query=hello&query2=world` // 返回结果如下:{ everything: ["evanbacon", "123"], query: "hello", query2: "world" }

更新 URL 参数

可以使用命令式 API 中的 router.setParams 函数来更新 URL 参数。更新 URL 参数不会向历史栈中新增任何内容。

下面的示例使用 <TextInput> 来更新搜索参数 q

src/app/search.tsx
import { useLocalSearchParams, router } from 'expo-router'; import { useState } from 'react'; import { TextInput, View } from 'react-native'; export default function Page() { const params = useLocalSearchParams<{ query?: string }>(); const [search, setSearch] = useState(params.query); return ( <TextInput value={search} onChangeText={search => { setSearch(search); router.setParams({ query: search }); }} placeholderTextColor="#A0A0A0" placeholder="搜索" style={{ borderRadius: 12, backgroundColor: '#fff', fontSize: 24, color: '#000', margin: 12, padding: 16, }} /> ); }

下面是一个使用 onPress 事件来更新路由参数 user 的示例:

src/app/[user].tsx
import { useLocalSearchParams, router } from 'expo-router'; import { Text } from 'react-native'; export default function User() { const params = useLocalSearchParams<{ user: string }>(); return ( <> <Text>User: {params.user}</Text> <Text onPress={() => router.setParams({ user: 'evan' })}>前往 Evan</Text> </> ); }

路由参数与搜索参数的区别

路由参数用于匹配路由,而搜索参数用于在路由之间传递数据。请看下面的结构,其中路由参数用于匹配 user 路由:

src
app
  index.tsx
  [user].tsxuser 是一个 路由参数

src/app/[user] 路由被匹配时,user 参数会传递给组件,并且绝不会是空值。搜索参数和路由参数可以一起使用,并且可以通过 useLocalSearchParamsuseGlobalSearchParams hooks 访问:

src/app/[user].tsx
import { useLocalSearchParams } from 'expo-router'; export default function User() { const { // 路由参数 user, // 一个可选的搜索参数。 tab, } = useLocalSearchParams<{ user: string; tab?: string }>(); console.log({ user, tab }); // 给定 URL:`/bacon?tab=projects`,会打印以下内容: // { user: 'bacon', tab: 'projects' } // 给定 URL:`/expo`,会打印以下内容: // { user: 'expo', tab: undefined } }

每当路由参数发生变化时,组件都会重新挂载。

src/app/[user].tsx
import { Text } from 'react-native'; import { router, useLocalSearchParams, Link } from 'expo-router'; export default function User() { // 这三种方式都会更改路由参数 `user`,并新增一个用户页面。 return ( <> <Text onPress={() => router.setParams({ user: 'evan' })}>前往 Evan</Text> <Text onPress={() => router.push('/mark')}>前往 Mark</Text> <Link href="/charlie">前往 Charlie</Link> </> ); }

哈希支持

URL 哈希 是 URL 中跟在 # 符号后面的字符串。它通常用于网站中链接到页面的特定部分,但也可以用于存储数据。Expo Router 将哈希视为一个名为 # 的特殊搜索参数。它可以使用与 搜索参数 相同的 hooks 和 API 进行访问和修改。

src/app/hash.tsx
import { Text } from 'react-native'; import { router, useLocalSearchParams, Link } from 'expo-router'; export default function User() { // 访问哈希 const { '#': hash } = useLocalSearchParams<{ '#': string }>(); return ( <> <Text onPress={() => router.setParams({ '#': 'my-hash' })}>设置一个新的哈希</Text> <Text onPress={() => router.push('/#my-hash')}>使用新的哈希进行推送</Text> <Link href="/#my-hash">带哈希的链接</Link> </> ); }

保留参数

某些 URL 参数会被 Expo Router 和 React Navigation 保留用于内部使用。请避免将以下名称用于你自己的参数,以免发生冲突:

  • screen
  • params
  • initial
  • state