在上一节“Hello React Navigation”中,我们定义了一个带有两个路由 (HomeDetails) 的原生Stack导航器,但是我们没有学习如何让用户从Home到导航Details(尽管我们已经学习了如何在我们的代码,但强迫我们的用户克隆我们的仓库并更改变路由以查看另一个屏幕可以说是人们可以想象的最糟糕的用户体验之一)。
如果这是一个网络浏览器,我们可以这样写:

  1. <a href="details.html">Go to Details</a>

另一种写法是:

  1. <a
  2. onClick={() => {
  3. window.location.href = 'details.html';
  4. }}
  5. >
  6. Go to Details
  7. </a>

我们将要做与后面类似的事,我们并不是要使用全局的window.location,我们将要使用navigation prop 传递到我们的屏幕组件。

跳转(导航)到新屏幕

  1. import * as React from 'react';
  2. import { Button, View, Text } from 'react-native';
  3. import { NavigationContainer } from '@react-navigation/native';
  4. import { createNativeStackNavigator } from '@react-navigation/native-stack';
  5. function HomeScreen({ navigation }) {
  6. return (
  7. <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
  8. <Text>Home Screen</Text>
  9. <Button
  10. title="Go to Details"
  11. onPress={() => navigation.navigate('Details')}
  12. />
  13. </View>
  14. );
  15. }

让我们分解一下:
navigation- 该navigation通过prop传递到每一个屏幕组件。(稍后将在”深入的导航道具”中对此进行详细介绍)。
navigate('Details')- 我们要调用 navigate函数来帮助用户跳到自己想去的屏幕。

如果我们navigation.navigate使用在未定义的导航的路由名称进行调用,它将在开发构建中打印错误,并且在生产构建中不会发生任何事情。换句话说,我们只能导航到在导航器上定义的路由——我们不能导航到任意组件。

所以我们现在有一个包含两哥路由的stack:(1)Home路由 (2)Details路由。如果我们从Details再次导航到Details会发生什么?

多次导航到同一个路由

  1. function DetailsScreen({ navigation }) {
  2. return (
  3. <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
  4. <Text>Details Screen</Text>
  5. <Button
  6. title="Go to Details... again"
  7. onPress={() => navigation.navigate('Details')}
  8. />
  9. </View>
  10. );
  11. }

如果你运行这段代码,你就会注意到,当你点击Go to Details... again的时候,什么也没有做!这是因为我们已经在Details这个路由上了。navigate 函数已经告诉你跳转到该屏幕上了。如果您已经在该屏幕上,那么它什么也不做是有道理的。
假设我们世界上想要跳转另一个Detail页面。 这是非常常见的去传递一些独特的数据(稍后我们会讨论params)。所以,我们可以更改navigatepush,这样就能达到我们要跳转到另一个Detail页面的意图而不用管现有的导航历史。

  1. <Button
  2. title="Go to Details... again"
  3. onPress={() => navigation.push('Details')}
  4. />

每次你调用push,我们都会向 navigation stack 中添加一个新的路由。当你调用 navigate 时, 首先尝试查找具有该名称的现有的路由,并且仅在 navigate stack中没有路由时, 才会push新的路由。

回退(go back)

当可以从活动屏幕返回时,navigate stack 提供的标题将自动包含一个后退按钮(如果navigate stack中只有一个屏幕,则没有任何内容可以返回,并且也是没有后退按钮的)。
有时你希望能够用编程的方式触发此行为,你可以使用 navigation.goBack();

  1. function DetailsScreen({ navigation }) {
  2. return (
  3. <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
  4. <Text>Details Screen</Text>
  5. <Button
  6. title="Go to Details... again"
  7. onPress={() => navigation.push('Details')}
  8. />
  9. <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
  10. // 使用编程的方式触发行为
  11. <Button title="Go back" onPress={() => navigation.goBack()} />
  12. </View>
  13. );
  14. }

在 Android 上,React Navigation 挂钩到硬件后退按钮,并goBack()在用户按下它时为您触发该功能,因此它的行为与用户所期待的是一样的。

另一个常见的需求是能够跳过多个屏幕——例如,如果您在navigate stack有很多个屏幕并且想要关闭所有屏幕去返回第一个屏幕(关闭navigate stack中间的路由,直接调回Home页面)。在这种情况下,我们知道我们想要返回Home, 所以我们可以使用navigate('Home')(注意不是push!你可以尝试一下,这两者之间有什么不同)。另一种选择是navigation.popToTop(),它返回到navigate stack中的第一个屏幕。

  1. function DetailsScreen({ navigation }) {
  2. return (
  3. <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
  4. <Text>Details Screen</Text>
  5. <Button
  6. title="Go to Details... again"
  7. onPress={() => navigation.push('Details')}
  8. />
  9. <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
  10. <Button title="Go back" onPress={() => navigation.goBack()} />
  11. // 回到第一个页面
  12. <Button
  13. title="Go back to first screen in stack"
  14. onPress={() => navigation.popToTop()}
  15. />
  16. </View>
  17. );
  18. }

总结

  • navigation.navigate('RouteName')如果它不在navigate stack中,则将新路由pushstack navigator,否则它会跳转到该屏幕。
  • 我们可以随意调用navigation.push('RouteName')多次,它会继续推送路由。
  • 标题栏将自动显示一个后退按钮,但你可以通过编程方式执行navigation.goBack()。在 Android 上,硬件后退按钮按预期工作。
  • 你可以使用返回到stack中的现有屏幕navigation.navigate('RouteName'),也可以使用navigation.popToTop()返回到堆栈中的第一个屏幕。
  • navigation道具可用于所有屏幕组件(在路由配置中定义为屏幕并由 React Navigation呈现为路由的组件)。