使用 URL 参数
编辑
学习如何在应用中访问和修改路由参数和搜索参数。
URL 参数包括 路由参数 和 搜索参数。Expo Router 提供 hooks 用于访问和修改这些参数。
路由参数和搜索参数的区别
路由参数是定义在 URL 路径中的动态片段,如 /profile/[user],其中 user 是路由参数。它们用于匹配路由。
搜索参数(也称为查询参数)是可以附加到 URL 上的可序列化字段,如 /profile?extra=info,其中 extra 是搜索参数。它们通常用于在页面之间传递数据。
本地与全局 URL 参数
在嵌套应用中,您常常会同时有 多个页面挂载。例如,当新的路由被推送时,堆栈中会同时保留前一页面和当前页面的内存。因此,Expo Router 提供了两种不同的 hooks 来访问 URL 参数:
- useLocalSearchParams:返回当前组件的 URL 参数。仅当全局 URL 符合路由时才会更新。
- useGlobalSearchParams:返回全局 URL,不考虑组件。它在每次 URL 参数更改时更新,并可能导致组件在后台非必要地更新。
hooks useGlobalSearchParams 和 useLocalSearchParams 允许您在组件内部访问这些参数,使您能够检索和利用这两种类型的 URL 参数。
这两个 hooks 的类型和访问方式相同。但唯一的区别是它们更新的频率。
下面的示例演示了 useLocalSearchParams 和 useGlobalSearchParams 之间的区别。它使用以下 app 目录结构:
app_layout.tsxindex.tsx[user].tsx1
根布局是一个堆栈导航器:
import { Stack } from 'expo-router'; export default function Layout() { return <Stack />; }
2
初始路由重定向到动态路由 app/[user].tsx,其 user=evanbacon:
import { Redirect } from 'expo-router'; export default function Route() { return <Redirect href="/evanbacon" />; }
3
动态路由 app/[user] 打印全局和本地 URL 参数(在此情况下为路由参数)。它还允许通过不同的 路由参数 推送同一路由的新实例:
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
当应用启动时,打印以下日志:
Local: evanbacon Global: evanbacon按下“Visit charlie”会推送新的 /[user] 实例,user=charlie,并记录以下内容:
# 这个日志来自新屏幕Local: charlie Global: charlie# 这个日志来自第一个屏幕Local: evanbacon Global: charlie按下“Visit james”会有类似的效果:
# 这个日志来自新屏幕,"/james"Local: james Global: james# 这个日志来自"/evanbacon"屏幕Local: evanbacon Global: james# 这个日志来自"/charlie"屏幕Local: charlie Global: james结果:
useGlobalSearchParams在 URL 路由参数 更改时使后台屏幕重新渲染。如果过度使用,可能会导致性能问题。- 全局重新渲染按堆栈顺序执行,因此第一个屏幕首先重新渲染,然后是 user=charlie 屏幕。
useLocalSearchParams在全局 URL 路由参数 更改时保持不变。您可以利用这种行为进行数据获取,以确保在返回时先前屏幕的数据仍然可用。
静态类型的 URL 参数
useLocalSearchParams 和 useGlobalSearchParams 都可以使用泛型进行静态类型化。以下是 user 路由参数的示例:
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=...)可以选择性地进行类型定义:
const { user, query } = useLocalSearchParams<{ user: string; query?: string }>(); // 给定 URL: `/evanbacon?query=hello` // 返回: { user: "evanbacon", query: "hello" }
与剩余语法(...)一起使用时,路由参数作为字符串数组返回:
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"] }
任何搜索参数将继续作为单独的字符串返回:
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>; } // 给定 URL: `/evanbacon/123?query=hello&query2=world` // 返回: { everything: ["evanbacon", "123"], query: "hello", query2: "world" }
更新 URL 参数
URL 参数可以使用 router.setParams 函数从命令式 API 更新。更新 URL 参数不会将任何内容推送到历史堆栈。
以下示例使用 <TextInput> 更新搜索参数 q:
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 的示例:
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 路由:
appindex.tsx[user].tsxuser 是一个 路由参数当匹配 app/[user] 路由时,user 参数传递给组件,并且始终不是空值。搜索参数和路由参数可以一起使用,并且可以通过 useLocalSearchParams 和 useGlobalSearchParams hooks 访问:
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 } }
每当路由参数更改时,组件将重新挂载。
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 访问和修改它。
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 内部使用。避免使用以下名称作为您自己的参数,以防止冲突:
screenparamsinitialstate