Skip to main content
Version: 7.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() {
const navigation = useNavigation();

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
>
Go to Details
</Button>
</View>
);
}

function DetailsScreen({ route }) {
const navigation = useNavigation();

/* 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
onPress={
() =>
navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
}
>
Go to Details... again
</Button>
<Button onPress={() => navigation.navigate('Home')}>Go to Home</Button>
<Button onPress={() => navigation.goBack()}>Go back</Button>
</View>
);
}
Try on Snack

初始参数

¥Initial params

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

¥You can also 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 in initialParams:

{
Details: {
screen: 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({
itemId: Math.floor(Math.random() * 100),
})
Try on Snack
注意

避免使用 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 as well. For example, let's say you have a screen with a "Create post" button, and the button opens a new screen to create a post. After creating the post, you want to pass the data for the post back to the previous screen.

为了实现这一点,你可以使用 popTo 方法返回上一个屏幕以及向其传递参数:

¥To achieve this, you can use the popTo method to go back to the previous screen as well as pass params to it:

function HomeScreen({ route }) {
const navigation = useNavigation();

// Use an effect to monitor the update to params
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
alert('New post: ' + route.params?.post);
}
}, [route.params?.post]);

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('CreatePost')}>
Create post
</Button>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</View>
);
}

function CreatePostScreen({ route }) {
const navigation = useNavigation();
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
onPress={() => {
// Pass params back to home screen
navigation.popTo('Home', { post: postText });
}}
>
Done
</Button>
</>
);
}
Try on Snack

在这里,按下 "完毕" 后,主屏幕的 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 a nested screen

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

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

navigation.navigate('More', {
screen: 'Settings',
params: { user: 'jane' },
})
Try on Snack

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

¥See Nesting navigators for more details on nesting.

参数中应该包含什么

¥What should be in params

Params 本质上是屏幕的选项。它们应该包含显示屏幕所需的最少数据,仅此而已。如果数据被多个屏幕使用,则应位于全局存储或全局缓存中。Params 不是为状态管理而设计的。

¥Params are essentially options for a screen. They should contain the minimal data required to show a screen, nothing more. If the data is used by multiple screens, it should be in a global store or global cache. Params is not designed for state management.

你可以将路由对象视为 URL。如果你的屏幕有一个 URL,该 URL 中应该包含什么?相同的原则适用于参数。想想访问购物网站;当你看到产品列表时,URL 通常包含类别名称、排序类型、任何过滤器等,而不是屏幕上显示的实际产品列表。

¥You can think of the route object as a URL. If your screen had a URL, what should be in the URL? The same principles apply to params. Think of visiting a shopping website; when you see product listings, the URL usually contains category name, type of sort, any filters etc., not 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. There are many reasons why this is a bad idea:

  • 相同的数据在多个地方重复。这可能会导致错误,例如即使用户对象在导航后发生更改,配置文件屏幕也会显示过时的数据。

    ¥The same data is 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.

  • 现在,导航到 Profile 屏幕的每个屏幕都需要知道如何获取用户对象 - 这增加了代码的复杂性。

    ¥Each screen that navigates to the Profile screen now needs to know how to fetch the user object - which increases the complexity of the code.

  • 屏幕的 URL(网络上的浏览器 URL 或原生上的深层链接)将包含用户对象。这有问题:

    ¥URLs to the screen (browser URL on the web, or deep links on native) will contain the user object. This is problematic:

    1. 由于用户对象在 URL 中,因此可以传递一个随机用户对象来表示不存在或个人资料中数据不正确的用户。

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

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

      ¥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.

    3. URL 可能变得非常长且难以阅读。

      ¥The URL can become very long and unreadable.

更好的方法是在参数中仅传递用户的 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