# Hello React Navigation

在 Web 浏览器中,可以使用锚点(<a>)标记链接到不同的页面。当用户单击链接时,URL 将被推送到浏览器历史记录堆栈。当用户按下“后退”按钮时,浏览器从历史记录堆栈的顶部弹出该项目,因此活动页面现在是先前访问的页面。 React Native 不像 Web 浏览器那样具有内置的全局历史堆栈概念,这就是 React Navigation 进入故事的地方。

React Navigation 的堆栈导航器(stack navigator)为您的应用程序提供了一种在屏幕之间转换和管理导航历史记录的方式。如果您的应用仅使用一个堆栈导航器,那么它在概念上类似于 Web 浏览器处理导航状态的方式 - 您的应用在用户与之交互时从导航堆栈中 push 和 pop 项目,使得用户看到不同的屏幕。它在 Web 浏览器和 React Navigation 中的工作方式之间的主要区别在于,React Navigation 提供了你可能期望的在 Android 和 iOS 中路由导航时的手势和动画

让我们从最常见的导航器 createStackNavigator 开始演示。

# 安装堆栈导航器(stack navigator)库

到目前为止,我们已经安装的库是导航器的构建块和基础共享库,而且 React Navigation 中的每种导航器都位于其自己的库中。 要使用堆栈导航器,我们需要安装 @react-navigation/stack

npm install @react-navigation/stack

@react-navigation/stack 依赖 @react-native-community/masked-view 以及我们在《入门指南》中安装的其他库。 如果尚未安装,请转到该页面并按照安装说明进行操作。

# 创建堆栈导航器(stack navigator)

createStackNavigator 是一个函数,该函数返回包含 2 个属性的对象:ScreenNavigator。 它们都是用于配置导航器的 React 组件。 导航器应包含 Screen 元素作为其子元素,以定义路由的配置。

NavigationContainer 是管理导航树并包含 导航状态 (opens new window)的组件。 该组件必须包装所有导航器结构。 通常,我们会在应用程序的根组件下渲染此组件,该组件通常是从 App.js 导出的组件。

// In App.js in a new project

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

function HomeScreen() {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Home Screen</Text>
    </View>
  );
}

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;
fsdfsd

如果运行此代码,您将看到一个屏幕,其中包含一个空的导航栏和一个包含 HomeScreen 组件的灰色内容区域(如上所示)。 您在导航栏和内容区域中看到的样式是堆栈导航器的默认配置,我们将在以后学习如何配置这些样式。

路由名称的大小写并不重要,你可以用小写的 home 或者大写的 Home, 由你决定。我们更喜欢把路由名大写。

Screen 唯一需要的配置是 namecomponent 属性,您可以在 堆栈导航器参考 (opens new window) 中了解更多可用的其他选项。

# 配置导航器

所有的路由配置都使用导航器的 props 来指定。 我们尚未将任何 props 传递给导航器,因此它仅使用默认配置。

让我们向堆栈导航器添加第二个屏幕,并将 Home 屏幕配置为首要渲染:

function DetailsScreen() {
  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <Text>Details Screen</Text>
    </View>
  );
}

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

现在我们的堆栈有两个路由,一个 Home 路由和一个 Details 路由。可以使用 Screen 组件指定路由。Screen 组件接受一个 name,它对应于我们将用来导航的路由的名称,以及一个组 component,它对应于它将渲染的组件。

这里,Home 路由对应于 HomeScreen 组件,Details 路由对应于 DetailsScreen 组件。堆栈的初始路由是 Home 路由。尝试将其更改为 Details 并重新加载应用程序(React Native 的 Fast Refresh 不会如你所期望的那样从 initialRouteName 更新更改),注意,你现在会看到 Details 屏幕。然后将其更改为 Home 并重新加载一次。

注意:component 接受的是组件,而不是渲染函数。不要传递内联函数(例如 component={() => <HomeScreen/>}),否则当父组件重新渲染时,你的组件会卸载和重新挂载失去所有状态。请参阅 传递额外的 props 以获得替代方案。

# 指定选项

导航器中的每个屏幕都可以为导航器指定一些选项,比如要在标题中渲染的标题。这些选项可以在每个屏幕组件的 options 属性中传递:

<Stack.Screen
  name="Home"
  component={HomeScreen}
  options={{ title: "Overview" }}
/>

有时,我们希望为导航器中的所有屏幕指定相同的选项。为此,我们可以向导航器传递一个 screenOptions 属性。

# 传递额外的属性

有时我们可能想将其他属性传递到 screen 上。 我们可以通过 2 种方法来做到这一点:

  1. 使用 React context (opens new window),并用上下文提供程序包装导航器,以将数据传递到屏幕(推荐)。
  2. Screen 使用渲染回调,而不要指定 component
<Stack.Screen name="Home">
  {(props) => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>

注意:默认情况下,React Navigation 将优化应用于 Screen 组件,以防止不必要的渲染。 使用渲染回调将删除这些优化。 因此,如果您使用渲染回调,则需要确保对屏幕组件使用 React.memoReact.PureComponent 以避免性能问题。

# 下一步是什么?

此时的自然问题是:“如何从 Home 路由转到 Details 路由?”。 下一部分将对此进行介绍。

# 总结

  • React Native 没有像 Web 浏览器那样的内置 API 用于导航。 React Navigation 为您提供此功能,以及 iOS 和 Android 手势和动画以在屏幕之间切换。
  • Stack.Navigator 是一个组件,它将路由配置作为其子级,并带有用于配置的额外 props 并渲染我们的内容。
  • 每个 Stack.Screen 组件都有一个 name ,它将作为路由的名称,而 component 则指定了要为该路由渲染的组件。 这些是 2 个必需的道具。
  • 要指定堆栈中的初始路由是什么,请提供为导航器指定 initialRouteName
  • 要指定特定于屏幕的选项,我们可以将 options 传递给 Stack.Screen,对于通用选项,我们可以将 screenOptions 传递给 Stack.Navigator