使用 URL 参数

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


URL 参数包括 路由参数查询参数。Expo Router 提供了用于访问和修改这些参数的钩子。

🌐 URL parameters include both route parameters and search parameters. Expo Router provides hooks for accessing and modifying these parameters.

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

🌐 Difference between route and search parameters

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

🌐 Route parameters are dynamic segments defined in a URL path, such as /profile/[user], where user is a route parameter. They are used to match a route.

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

🌐 Search parameters (also known as query params) are serializable fields that can be appended to a URL, such as /profile?extra=info, where extra is a search parameter. They are commonly used to pass data between pages.

本地与全局 URL 参数

🌐 Local versus global URL parameters

在嵌套应用中,你经常会同时有多个页面挂载。例如,当新的路由被推入时,栈中会同时存在前一个页面和当前页面的内存。因此,Expo Router 提供了两种不同的钩子来访问 URL 参数:

🌐 In nested apps, you'll often have multiple pages mounted at the same time. For example, a stack has the previous page and current page in memory when a new route is pushed. Because of this, Expo Router provides two different hooks for accessing URL parameters:

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

钩子 useGlobalSearchParamsuseLocalSearchParams 允许你在组件中访问这些参数,使你能够获取并使用两种类型的 URL 参数。

🌐 The hooks useGlobalSearchParams and useLocalSearchParams allow you to access these parameters within your components, enabling you to retrieve and utilize both types of URL parameters.

这两个钩子的类型和访问方式相同。唯一的区别是它们更新的频率不同。

🌐 Both hooks are typed and accessed the same way. However, the only difference is how frequently they update.

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

🌐 The example below demonstrates the difference between useLocalSearchParams and useGlobalSearchParams. It uses the following app directory structure:

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

1

根布局是一个堆栈导航器:

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

2

初始路由重定向到动态路由 app/[user].tsx,其中 user=evanbacon

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

3

动态路由 app/[user] 会打印全局和局部的 URL 参数(在这种情况下是路由参数)。它还允许使用不同的 路由参数 推入同一路由的新实例:

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}`}> Visit {friend} </Link> ))} </View> ); }

4

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

🌐 When the app starts, the following log is printed:

Terminal
Local: evanbacon Global: evanbacon

点击“访问 charlie”会推送一个新的 /[user] 实例,user=charlie,并记录以下内容:

🌐 Pressing "Visit charlie" pushes a new instance of /[user] with user=charlie, and logs the following:

Terminal
# This log came from the new screenLocal: charlie Global: charlie# This log came from the first screenLocal: evanbacon Global: charlie

点击“访问 James”有类似的效果:

🌐 Pressing "Visit james" has a similar effect:

Terminal
# This log came from the new, "/james" screenLocal: james Global: james# This log came from the "/evanbacon" screenLocal: evanbacon Global: james# This log came from the "/charlie" screenLocal: charlie Global: james

结果:

  • useGlobalSearchParams 会在 URL 路由参数 改变时重新渲染背景屏幕。如果过度使用,可能会导致性能问题。
  • 全局重新渲染按堆栈顺序执行,因此第一个屏幕会先重新渲染,然后 user=charlie 屏幕随后重新渲染。
  • useLocalSearchParams 保持不变,即使全局 URL 路由参数 改变。你可以利用这种行为进行数据获取,以确保在返回时前一个界面的数据仍然可用。

静态类型的 URL 参数

🌐 Statically-typed URL parameters

useLocalSearchParamsuseGlobalSearchParams 都可以使用泛型进行静态类型定义。以下是 user 路由参数的示例:

🌐 Both the useLocalSearchParams and useGlobalSearchParams can be statically typed using a generic. The following is an example for the user route parameter:

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>; } // Given the URL: `/evanbacon` // The following is returned: { user: "evanbacon" }

任何搜索参数(例如 ?query=...)可以选择性地输入:

🌐 Any search parameters (for example, ?query=...) can be typed optionally:

app/[user].tsx
const { user, query } = useLocalSearchParams<{ user: string; query?: string }>(); // Given the URL: `/evanbacon?query=hello` // The following is returned: { user: "evanbacon", query: "hello" }

与剩余语法(...)一起使用时,路由参数将作为字符串数组返回:

🌐 When used with the rest syntax (...), route parameters are returned as a string array:

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>; } // Given the URL: `/evanbacon/123` // The following is returned: { everything: ["evanbacon", "123"] }

任何搜索参数将继续以单独的字符串形式返回:

🌐 Any search parameters will continue to be returned as individual strings:

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: {user}</Text>; } // Given the URL: `/evanbacon/123?query=hello&query2=world` // The following is returned: { everything: ["evanbacon", "123"], query: "hello", query2: "world" }

更新 URL 参数

🌐 Updating URL parameters

可以使用命令式 API 中的 router.setParams 函数来更新 URL 参数。更新 URL 参数不会向历史记录栈中添加任何新条目。

🌐 URL parameters can be updated using the router.setParams function from the imperative API. Updating a URL parameter will not push anything new to the history stack.

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

🌐 The following example uses a <TextInput> to update the search parameter q:

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="Search" style={{ borderRadius: 12, backgroundColor: '#fff', fontSize: 24, color: '#000', margin: 12, padding: 16, }} /> ); }

以下是使用 onPress 事件更新路由参数 user 的示例:

🌐 Here is an example using an onPress event to update the route parameter user:

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' })}>Go to Evan</Text> </> ); }

路由参数与搜索参数

🌐 Route parameters versus search parameters

路由参数用于匹配路由,而查询参数用于在路由之间传递数据。考虑以下结构,其中路由参数用于匹配 user 路由:

🌐 Route parameters are used to match a route, while search parameters are used to pass data between routes. Consider the following structure, where a route parameter is used to match the user route:

app
index.tsx
[user].tsxuser is a route parameter

当匹配到 app/[user] 路由时,user 参数会传递给组件,并且永远不会是 null 或 undefined 值。搜索参数和路由参数可以一起使用,并且可以通过 useLocalSearchParamsuseGlobalSearchParams 钩子访问:

🌐 When the app/[user] route is matched, the user parameter is passed to the component and never a nullish value. Both search and route parameters can be used together and are accessible with the useLocalSearchParams and useGlobalSearchParams hooks:

app/[user].tsx
import { useLocalSearchParams } from 'expo-router'; export default function User() { const { // The route parameter user, // An optional search parameter. tab, } = useLocalSearchParams<{ user: string; tab?: string }>(); console.log({ user, tab }); // Given the URL: `/bacon?tab=projects`, the following is printed: // { user: 'bacon', tab: 'projects' } // Given the URL: `/expo`, the following is printed: // { user: 'expo', tab: undefined } }

每当更改路由参数时,组件都会重新挂载。

🌐 Whenever a route parameter is changed, the component will re-mount.

app/[user].tsx
import { Text } from 'react-native'; import { router, useLocalSearchParams, Link } from 'expo-router'; export default function User() { // All three of these will change the route parameter `user`, and add a new user page. return ( <> <Text onPress={() => router.setParams({ user: 'evan' })}>Go to Evan</Text> <Text onPress={() => router.push('/mark')}>Go to Mark</Text> <Link href="/charlie">Go to Charlie</Link> </> ); }

数组支持

🌐 Array support

出现多次的 URL 参数将会被分组为一个数组。

🌐 URL parameters that are present multiple times will be grouped together as an array.

app/hash.tsx
import { router, useLocalSearchParams } from 'expo-router'; export default function Route() { // If the current URL is `/route?myParam=1&myParam=2 const { myParam } = useLocalSearchParams(); // myParam === ["1", "2"] }

*/}

哈希支持

🌐 Hash support

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

🌐 The URL hash is a string that follows the # symbol in a URL. It is commonly used on websites to link to a specific section of a page, but it can also be used to store data. Expo Router treats the hash as a special search parameter using the name #. It can be accessed and modified using the same hooks and APIs from search parameters.

app/hash.tsx
import { Text } from 'react-native'; import { router, useLocalSearchParams, Link } from 'expo-router'; export default function User() { // Access the hash const { '#': hash } = useLocalSearchParams<{ '#': string }>(); return ( <> <Text onPress={() => router.setParams({ '#': 'my-hash' })}>Set a new hash</Text> <Text onPress={() => router.push('/#my-hash')}>Push with a new hash</Text> <Link href="/#my-hash">Link with a hash</Link> </> ); }

保留参数

🌐 Reserved parameters

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

🌐 Certain URL parameters are reserved for internal use by Expo Router and React Navigation. Avoid using the following names for your own parameters to prevent conflicts:

  • screen
  • params
  • initial
  • state