# 在屏幕之间跳转

在上一节 “Hello React Navigation” 中,我们定义了具有两条路由(“Home”“Details”)的堆栈导航器,但是我们没有学习如何让用户从 Home 导航到 Details(尽管我们确实学习了如何更改 “ Hello React Navigation”)。 代码中的初始路由,但是强迫用户克隆我们的存储库并更改代码中的路径以查看另一个屏幕,可以说是用户可能想到的最糟糕的用户体验之一。

如果这是一个网络浏览器,我们将能够编写如下内容:

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

另一种写法是:

<a
  onClick={() => {
    window.location.href = 'details.html';
  }}
>
  Go to Details
</a>

我们将执行与后者类似的操作,但不使用全局 window.location,而是使用向下传递到屏幕组件的 navigation 属性。

# 导航到一个新屏幕

import * as React from "react";
import { Button, View, Text } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate("Details")}
      />
    </View>
  );
}

让我们分解一下:

  • navigation - navigation prop 会传递到堆栈导航器中的每个 屏幕组件
  • navigate('Details') - 我们调用 navigate 方法(在navigation prop 上–很难命名!),其名称为我们要将用户跳转到的路由的名称。

如果我们使用导航器中未定义的路由名称调用 navigation.navigate,它将在开发版本中显示错误,而在生产版本中则不会发生任何错误。 换句话说,我们只能导航到导航器上已定义的路由,而不能导航到任意组件。

所以我们现在有两个路由的堆栈: 1) Home 路由 2) Details 路由。如果我们从 Details 屏幕再次导航到 Details 路线会发生什么?

# 多次导航到一个路由

function DetailsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Details Screen</Text>
      <Button
        title="Go to Details... again"
        onPress={() => navigation.navigate("Details")}
      />
    </View>
  );
}

如果运行此代码,您会注意到,当您点击 “Go to Details... again” 时,它不会执行任何操作! 这是因为我们已经在 “Details” 路由上。 navigate 功能大致意味着 “go to this screen”,并且如果您已经在该屏幕上,则说它什么也不做是有道理的。

假设我们实际上要添加另一个 Details 屏幕。 在您向每个路由传递特定数据的情况下,这是很常见的(稍后我们将讨论 params!)。 为此,我们可以将 navigate 更改为 push。 这样,无论现有的导航历史如何,我们都可以表达出添加另一路由的意图。

<Button
  title="Go to Details... again"
  onPress={() => navigation.push("Details")}
/>

每次您调用 push 时,我们都会向导航堆栈添加一条新路由。 当您调用 navigate 时,它首先尝试查找具有该名称的现有路由,并且仅在堆栈中没有新路由时才推送新路由。

# 返回

当可以从活动屏幕返回时,堆栈导航器提供的标题将自动包含一个后退按钮(如果导航堆栈中只有一个屏幕,则无法返回任何内容,因此没有返回键)。

有时,您可能希望能够以编程方式触发此行为,为此,您可以使用 navigation.goBack();。

function DetailsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Details Screen</Text>
      <Button
        title="Go to Details... again"
        onPress={() => navigation.push("Details")}
      />
      <Button title="Go to Home" onPress={() => navigation.navigate("Home")} />
      <Button title="Go back" onPress={() => navigation.goBack()} />
    </View>
  );
}

在 Android 上,React Navigation 会挂接到硬件后退按钮,并在用户按下它时为您触发 goBack() 函数,因此它的行为与用户期望的一样。

另一个常见的要求是能够返回多个屏幕 -例如,如果您在堆栈深处有多个屏幕,并且想要解散所有这些屏幕以返回到第一个屏幕。 在这种情况下,我们知道我们想回到 Home,所以我们可以使用 navigate('Home')(而不是 push!尝试一下,看看有什么不同)。 另一个选择是 navigation.popToTop(),它返回到堆栈中的第一个屏幕。

function DetailsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Details Screen</Text>
      <Button
        title="Go to Details... again"
        onPress={() => navigation.push("Details")}
      />
      <Button title="Go to Home" onPress={() => navigation.navigate("Home")} />
      <Button title="Go back" onPress={() => navigation.goBack()} />
      <Button
        title="Go back to first screen in stack"
        onPress={() => navigation.popToTop()}
      />
    </View>
  );
}

# 总结

  • navigation.navigate('RouteName') 将新路由推送到堆栈导航器(如果尚未在堆栈中),否则将跳转到该屏幕。
  • 我们可以根据需要多次调用 navigation.push('RouteName'),它将继续推送路由。
  • 标题栏将自动显示一个后退按钮,但您可以通过调用 Navigation.goBack() 以编程方式返回。 在 Android 上,硬件后退按钮将按预期工作。
  • 您可以使用 navigation.navigate('RouteName') 返回到堆栈中的现有屏幕,并可以使用 navigation.popToTop() 返回到堆栈中的第一个屏幕。
  • navigation 属性可用于所有屏幕组件(在路由配置中定义为屏幕并由 React Navigation 呈现为路由的组件)。