Skip to main content
Version: 6.x

将参数传递给路由

还记得我说过“稍后我们谈论 params 时会详细介绍这一点!”吗?好吧,时机已经到了。

¥Remember when I said "more on that later when we talk about params!"? Well, the time has come.

现在我们知道了如何 创建一个带有一些路由的堆栈导航器在这些路由之间导航,让我们看看当我们导航到路由时如何将数据传递给路由。

¥Now that we know how to create a stack navigator with some routes and navigate between those routes, let's look at how we can pass data to routes when we navigate to them.

这有两部分:

¥There are two pieces to this:

  1. 通过将参数放入对象中作为 navigation.navigate 函数的第二个参数来将参数传递给路由:navigation.navigate('RouteName', { /* params go here */ })

    ¥Pass params to a route by putting them in an object as a second parameter to the navigation.navigate function: navigation.navigate('RouteName', { /* params go here */ })

  2. 读取屏幕组件中的参数:route.params

    ¥Read the params in your screen component: route.params.

注意

我们建议你传递的参数是 JSON 可序列化的。这样,你将能够使用 状态持续性,并且你的屏幕组件将具有实现 深层链接 的正确合同。

¥We recommend that the params you pass are JSON-serializable. That way, you'll be able to use state persistence and your screen components will have the right contract for implementing deep linking.

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>
);
}

初始参数

¥Initial params

你可以将一些初始参数传递到屏幕。如果你在导航到此屏幕时未指定任何参数,则将使用初始参数。它们也与你传递的任何参数浅层合并。初始参数可以使用 initialParams 属性指定:

¥You can pass some initial params to a screen. If you didn't specify any params when navigating to this screen, the initial params will be used. They are also shallow merged with any params that you pass. Initial params can be specified with an initialParams prop:

<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>

更新参数

¥Updating params

屏幕还可以更新它们的参数,就像它们可以更新它们的状态一样。navigation.setParams 方法允许你更新屏幕的参数。请参阅 setParams 的 API 参考 了解更多详细信息。

¥Screens can also update their params, like they can update their state. The navigation.setParams method lets you update the params of a screen. Refer to the API reference for setParams for more details.

基本用法:

¥Basic usage:

navigation.setParams({
query: 'someText',
});
注意

避免使用 setParams 来更新屏幕选项,如 title 等。如果需要更新选项,请使用 setOptions 代替。

¥Avoid using setParams to update screen options such as title etc. If you need to update options, use setOptions instead.

将参数传递到上一个屏幕

¥Passing params to a previous screen

参数不仅对于将一些数据传递到新屏幕有用,而且对于将数据传递到前一个屏幕也很有用。例如,假设你有一个带有创建帖子按钮的屏幕,并且创建帖子按钮会打开一个新屏幕来创建帖子。创建帖子后,你希望将帖子的数据传递回上一屏幕。

¥Params aren't only useful for passing some data to a new screen, but they can also be useful to pass data to a previous screen too. For example, let's say you have a screen with a create post button, and the create post button opens a new screen to create a post. After creating the post, you want to pass the data for the post back to previous screen.

要实现此目的,你可以使用 navigate 方法,如果屏幕已存在,则该方法的作用类似于 goBack。你可以通过 paramsnavigate 来传回数据:

¥To achieve this, you can use the navigate method, which acts like goBack if the screen already exists. You can pass the params with navigate to pass the data back:

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 中传递的帖子文本。

¥Here, after you press "Done", the home screen's route.params will be updated to reflect the post text that you passed in navigate.

将参数传递给嵌套导航器

¥Passing params to nested navigators

如果你有嵌套导航器,则需要以不同的方式传递参数。例如,假设你在 Account 屏幕内有一个导航器,并且想要将参数传递到该导航器内的 Settings 屏幕。然后你可以传递参数如下:

¥If you have nested navigators, you need to pass params a bit differently. For example, say you have a navigator inside the Account screen, and want to pass params to the Settings screen inside that navigator. Then you can pass params as following:

navigation.navigate('Account', {
screen: 'Settings',
params: { user: 'jane' },
});

有关嵌套的更多详细信息,请参阅 嵌套导航器

¥See Nesting navigators for more details on nesting.

参数中应该包含什么

¥What should be in params

了解参数中应该包含什么类型的数据很重要。参数就像屏幕的选项。它们应该只包含用于配置屏幕中显示内容的信息。避免传递将在屏幕本身上显示的完整数据(例如传递用户 ID 而不是用户对象)。还要避免传递多个屏幕使用的数据,此类数据应该存储在全局存储中。

¥It's important to understand what kind of data should be in params. Params are like options for a screen. They should only contain information to configure what's displayed in the screen. Avoid passing the full data which will be displayed on the screen itself (e.g. pass a user id instead of user object). Also avoid passing data which is used by multiple screens, such data should be in a global store.

你还可以将路由对象视为 URL。如果你的屏幕有一个 URL,该 URL 中应该包含什么?参数不应包含你认为不应出现在 URL 中的数据。这通常意味着你应该保留尽可能少的数据来确定屏幕是什么。想象一下访问一个购物网站,当你看到产品列表时,URL 通常包含类别名称、排序类型、任何过滤器等,但它不包含屏幕上显示的实际产品列表。

¥You can also think of the route object like a URL. If your screen had a URL, what should be in the URL? Params shouldn't contain data that you think should not be in the URL. This often means that you should keep as little data as possible needed to determine what the screen is. Think of visiting a shopping website, when you are seeing product listings, the URL usually contains category name, type of sort, any filters etc., it doesn't contain the actual list of products displayed on the screen.

例如,假设你有 Profile 屏幕。导航到它时,你可能会想在参数中传递用户对象:

¥For example, say if you have a Profile screen. When navigating to it, you might be tempted to pass the user object in the params:

// Don't do this
navigation.navigate('Profile', {
user: {
id: 'jane',
firstName: 'Jane',
lastName: 'Done',
age: 25,
},
});

这看起来很方便,并且允许你使用 route.params.user 访问用户对象,而无需任何额外的工作。

¥This looks convenient, and lets you access the user objects with route.params.user without any extra work.

然而,这是一种反模式。用户对象等数据应该位于全局存储中,而不是导航状态中。否则,相同的数据会在多个地方重复。这可能会导致错误,例如即使用户对象在导航后发生更改,配置文件屏幕也会显示过时的数据。

¥However, this is an anti-pattern. Data such as user objects should be in your global store instead of the navigation state. Otherwise you have the same data duplicated in multiple places. This can lead to bugs such as the profile screen showing outdated data even if the user object has changed after navigation.

通过深层链接或在 Web 上链接到屏幕也会出现问题,因为:

¥It also becomes problematic to link to the screen via deep linking or on the Web, since:

  1. URL 是屏幕的表示,因此它还需要包含参数,即完整的用户对象,这可能会使 URL 非常长且难以阅读

    ¥The URL is a representation of the screen, so it also needs to contain the params, i.e. full user object, which can make the URL very long and unreadable

  2. 由于用户对象位于 URL 中,因此可以传递代表不存在的用户或配置文件中的不正确数据的随机用户对象

    ¥Since the user object is in the URL, it's possible to pass a random user object representing a user which doesn't exist, or has incorrect data in the profile

  3. 如果用户对象未传递或格式不正确,则可能会导致崩溃,因为屏幕不知道如何处理它

    ¥If the user object isn't passed, or improperly formatted, this could result in crashes as the screen won't know how to handle it

更好的方法是在参数中仅传递用户的 ID:

¥A better way is to pass only the ID of the user in params:

navigation.navigate('Profile', { userId: 'jane' });

现在,你可以使用传递的 userId 从你的全局存储中获取用户。这消除了许多问题,例如过时的数据或有问题的 URL。

¥Now, you can use the passed userId to grab the user from your global store. This eliminates a host of issues such as outdated data, or problematic URLs.

参数中应包含的内容的一些示例如下:

¥Some examples of what should be in params are:

  1. ID,如用户 ID、项目 ID 等,例如 navigation.navigate('Profile', { userId: 'Jane' })

    ¥IDs like user id, item id etc., e.g. navigation.navigate('Profile', { userId: 'Jane' })

  2. 当你有一个项目列表时,用于排序、过滤数据等的参数,例如 navigation.navigate('Feeds', { sortBy: 'latest' })

    ¥Params for sorting, filtering data etc. when you have a list of items, e.g. navigation.navigate('Feeds', { sortBy: 'latest' })

  3. 时间戳、页码或分页光标,例如 navigation.navigate('Chat', { beforeTime: 1603897152675 })

    ¥Timestamps, page numbers or cursors for pagination, e.g. navigation.navigate('Chat', { beforeTime: 1603897152675 })

  4. 用于填充屏幕上的输入以组成某些内容的数据,例如 navigation.navigate('ComposeTweet', { title: 'Hello world!' })

    ¥Data to fill inputs on a screen to compose something, e.g. navigation.navigate('ComposeTweet', { title: 'Hello world!' })

本质上,在参数中传递识别屏幕所需的最少数据,在很多情况下,这仅仅意味着传递对象的 ID,而不是传递完整的对象。将应用数据与导航状态分开。

¥In essence, pass the least amount of data required to identify a screen in params, for a lot of cases, this simply means passing the ID of an object instead of passing a full object. Keep your application data separate from the navigation state.

概括

¥Summary

  • navigatepush 接受可选的第二个参数,以便你将参数传递到你要导航到的路由。例如:navigation.navigate('RouteName', { paramName: 'value' })

    ¥navigate and push accept an optional second argument to let you pass parameters to the route you are navigating to. For example: navigation.navigate('RouteName', { paramName: 'value' }).

  • 你可以通过屏幕内的 route.params 读取参数

    ¥You can read the params through route.params inside a screen

  • 你可以使用 navigation.setParams 更新屏幕参数

    ¥You can update the screen's params with navigation.setParams

  • 初始参数可以通过 Screen 上的 initialParams 属性传递

    ¥Initial params can be passed via the initialParams prop on Screen

  • 参数应包含显示屏幕所需的最少数据,仅此而已

    ¥Params should contain the minimal data required to show a screen, nothing more