向路由传递参数
还记得我说过“我们将在谈论 `params` 时再详细说明吗?” 现在是时候了。
现在我们已经知道如何 创建一个带有路由的堆栈导航器 以及如何 在这些路由之间导航,让我们看看如何在导航到路由时向路由传递数据。
这分为两部分
-
通过将参数放在一个对象中作为 `navigation.navigate` 函数的第二个参数来将参数传递给路由:`navigation.navigate('RouteName', { /* 参数在此处 */ })`
-
在屏幕组件中读取参数:`route.params`。
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
</View>
);
}
function DetailsScreen({ route, navigation }) {
/* 2. Get the param */
const { itemId, otherParam } = route.params;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
title="Go to Details... again"
onPress={() =>
navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
初始参数
您可以向屏幕传递一些初始参数。如果您在导航到此屏幕时没有指定任何参数,则将使用初始参数。它们也会与您传递的任何参数进行浅合并。可以使用 initialParams
属性指定初始参数。
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
更新参数
屏幕也可以更新其参数,就像它们可以更新其状态一样。navigation.setParams
方法允许您更新屏幕的参数。有关更多详细信息,请参阅 setParams
的 API 参考。
基本用法
navigation.setParams({
query: 'someText',
});
避免使用 setParams
更新屏幕选项,例如 title
等。如果您需要更新选项,请改用 setOptions
。
将参数传递给上一个屏幕
参数不仅对将一些数据传递给新屏幕有用,而且对将数据传递给上一个屏幕也有用。例如,假设您有一个带有创建帖子按钮的屏幕,并且创建帖子按钮会打开一个新屏幕来创建帖子。创建帖子后,您希望将帖子的数据传递回上一个屏幕。
要实现此目的,您可以使用 navigate
方法,如果屏幕已存在,该方法就像 goBack
一样。您可以使用 navigate
传递 params
将数据传递回去。
function HomeScreen({ navigation, route }) {
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
}
}, [route.params?.post]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Create post"
onPress={() => navigation.navigate('CreatePost')}
/>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</View>
);
}
function CreatePostScreen({ navigation, route }) {
const [postText, setPostText] = React.useState('');
return (
<>
<TextInput
multiline
placeholder="What's on your mind?"
style={{ height: 200, padding: 10, backgroundColor: 'white' }}
value={postText}
onChangeText={setPostText}
/>
<Button
title="Done"
onPress={() => {
// Pass and merge params back to home screen
navigation.navigate({
name: 'Home',
params: { post: postText },
merge: true,
});
}}
/>
</>
);
}
在这里,在您按下“完成”后,主屏幕的 route.params
将更新以反映您在 navigate
中传递的帖子文本。
将参数传递给嵌套导航器
如果您有嵌套导航器,则需要以略微不同的方式传递参数。例如,假设您在 Account
屏幕内有一个导航器,并且想要将参数传递给该导航器内的 Settings
屏幕。然后您可以按以下方式传递参数
navigation.navigate('Account', {
screen: 'Settings',
params: { user: 'jane' },
});
有关嵌套的更多详细信息,请参阅 嵌套导航器。
参数中应该包含什么内容
了解参数中应该包含哪些数据非常重要。参数就像屏幕的选项。它们应该只包含配置屏幕显示内容的信息。避免传递将在屏幕本身显示的完整数据(例如,传递用户 ID 而不是用户对象)。此外,避免传递多个屏幕使用的數據,此类数据应该存储在全局存储中。
您还可以将路由对象视为 URL。如果您的屏幕有 URL,URL 中应该包含什么内容?参数不应该包含您认为不应该出现在 URL 中的数据。这通常意味着您应该尽可能少地保留确定屏幕内容所需的数据。想想访问购物网站,当您看到产品列表时,URL 通常包含类别名称、排序类型、任何过滤器等,它不包含屏幕上显示的实际产品列表。
例如,假设您有一个 Profile
屏幕。导航到它时,您可能很想在参数中传递用户对象
// Don't do this
navigation.navigate('Profile', {
user: {
id: 'jane',
firstName: 'Jane',
lastName: 'Done',
age: 25,
},
});
这看起来很方便,并且让您无需任何额外工作即可使用 route.params.user
访问用户对象。
但是,这是一种反模式。用户对象等数据应该存储在您的全局存储中,而不是导航状态中。否则,您将在多个地方重复相同的数据。这会导致错误,例如,即使用户对象在导航后已更改,配置文件屏幕也会显示过时的数据。
通过深度链接或在 Web 上链接到屏幕也会变得很麻烦,因为
- URL 是屏幕的表示,因此它也需要包含参数,即完整的用户对象,这会使 URL 变得非常长且难以阅读
- 由于用户对象位于 URL 中,因此可以传递表示不存在的用户或配置文件中包含不正确数据的随机用户对象
- 如果用户对象未传递或格式不正确,这会导致崩溃,因为屏幕将不知道如何处理它
更好的方法是只在参数中传递用户的 ID。
navigation.navigate('Profile', { userId: 'jane' });
现在,您可以使用传递的 userId
从全局存储中获取用户。这消除了许多问题,例如过时数据或有问题的 URL。
参数中应该包含的一些示例:
- ID,例如用户 ID、项目 ID 等,例如
navigation.navigate('Profile', { userId: 'Jane' })
- 当您有一系列项目时,用于排序、过滤数据等的参数,例如
navigation.navigate('Feeds', { sortBy: 'latest' })
- 用于分页的时间戳、页码或游标,例如
navigation.navigate('Chat', { beforeTime: 1603897152675 })
- 用于在屏幕上填充输入以撰写内容的数据,例如
navigation.navigate('ComposeTweet', { title: 'Hello world!' })
本质上,在参数中传递识别屏幕所需的最少数据,在很多情况下,这仅仅意味着传递对象的 ID 而不是传递整个对象。将应用程序数据与导航状态分开。
总结
navigate
和push
接受一个可选的第二个参数,允许您将参数传递给您要导航到的路由。例如:navigation.navigate('RouteName', { paramName: 'value' })
。- 您可以在屏幕内通过
route.params
读取参数 - 您可以使用
navigation.setParams
更新屏幕的参数 - 初始参数可以通过
Screen
上的initialParams
属性传递 - 参数应包含显示屏幕所需的最小数据,仅此而已