还记得我说过“稍后我们再谈params!”时说的更多吗?嗯,时候到了。
现在我们知道如何创建一个带有一些路由的Native stack Navigator并在这些路由之间跳转,让我们看看当我们导航到路由时是怎么将数据传递给路由里面的。
一共有两个部分:
- 通过将参数作为函数的第二个参数放入对象中,将参数传递给路由
navigation.navigate:navigation.navigate('RouteName', { /* params go here */ }) - 跳转后的屏幕组件中的参数(接收参数):
route.params.我们建议您传递的参数是 可序列化JSON数据。这样,您将能够使用状态持久性,并且您的屏幕组件将拥有实现深度链接的正确契约。
function HomeScreen({ navigation }) {return (<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}><Text>Home Screen</Text><Buttontitle="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><Buttontitle="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>);}
更新参数
屏幕也可以更新他们自身的参数,就像他们可以更新他们的状态(state)一样。navigation.setParams方法允许你更新屏幕的参数。有关详细信息,请参阅API 参考setParams。
基本用法:
navigation.setParams({query: 'someText',});
注意: 避免使用
setParams更新屏幕选项等title。如果你需要更新选项,请setOptions改用。 参数和选项是不同的。
初始化参数
你还可以将一些初始参数传递给屏幕。如果你在导航到此屏幕时没有指定任何参数,就将使用初始参数。它们也与您传递的任何参数浅合并。可以使用initialParams prop属性指定初始参数:
<Stack.Screenname="Details"component={DetailsScreen}initialParams={{ itemId: 42 }}/>
将参数传递到之前的一个屏幕
参数不仅可用于将某些数据传递到新屏幕,而且还可用于将数据传递到前一个(上一层)屏幕。
例如,假设你有一个带有创建帖子按钮的屏幕,而创建帖子按钮会打开一个新屏幕来创建帖子。创建帖子完成后,你希望将帖子的数据传递回上一个屏幕。
此时,你可以使用navigate方法,该方法的作用就像goBack屏幕已经存在一样。您可以通过paramswithnavigate将数据传回:
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' }}><Buttontitle="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 (<><TextInputmultilineplaceholder="What's on your mind?"style={{ height: 200, padding: 10, backgroundColor: 'white' }}value={postText}onChangeText={setPostText}/><Buttontitle="Done"onPress={() => {// Pass and merge params back to home screen// 合并参数回到Home屏幕navigation.navigate({name: 'Home',params: { post: postText },merge: true,});}}/></>);}
在这里,按下“Done”后,Home屏幕route.params将更新来展示你输入的帖子文本。
将参数传递给嵌套的导航器
如果你有嵌套的导航器,则需要以不同的方式传递参数。例如,假设你在Account屏幕内有一个导航器,并且想要将参数传递给该导航器内的屏幕Settings。然后你可以传递参数如下:
navigation.navigate('Account', {screen: 'Settings',params: { user: 'jane' },});
有关嵌套的更多详细信息,请参阅嵌套导航器。
参数中应该包含什么?
了解 params 中应该包含什么样的数据是非常重要的。
参数就像屏幕的选项,它们应该只包含配置屏幕显示内容的信息。避免传递将显示在屏幕本身上的完整数据(例如传递用户 ID 而不是用户对象)。还要避免传递多个屏幕使用的数据,这些数据应该在全局存储中。
你也可以把路由对象想象成一个 URL。如果您的屏幕有一个 URL,那么 URL 中应该是什么?参数不应包含您认为不应出现在 URL 中的数据。这通常意味着你应该尽可能少的保留确定屏幕是什么所需的数据。想想访问一个购物网站,当你看到产品列表时,URL 通常包含类别名称、排序类型、任何过滤器等,它不包含屏幕上显示的实际产品列表。
例如,假设您有Profile屏幕。导航到它时,您可能想在参数中传递用户对象:
// 重要的事情说三遍: 千万不要这样做!// 重要的事情说三遍: 千万不要这样做!// 重要的事情说三遍: 千万不要这样做! 传递一个用户ID就可以了navigation.navigate('Profile', {user: {id: 'jane',firstName: 'Jane',lastName: 'Done',age: 25,},});
这看起来很方便,并且让你接收route.params.user不需要任何额外工作即可访问用户对象。
但是,这是一种反模式。例如用户对象之类的数据应该在你的全局存储中而不是导航状态中。否则,你会在多个地方重复相同的数据。这可能会导致错误,例如配置文件屏幕显示过时数据,即使用户对象在导航后已更改。
通过深度链接或在 Web 上链接到屏幕也会出现问题,因为:
- URL是屏幕的表示,所以它还需要包含参数,即完整的用户对象,这会使URL变得很长且不可读
- 由于用户对象在 URL 中,因此可以传递一个随机用户对象,该用户对象代表不存在的用户,或者配置文件中的数据不正确
- 如果用户对象没有被传递,或者格式不正确,这可能会导致崩溃,因为屏幕不知道如何处理它
更好的方法是在 params 中只传递用户的 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 - 初始参数可以通过
initialParams道具传递Screen - 参数应该包含显示屏幕所需的最少数据,仅此而已
