你好 React 导航
在网络浏览器中,你可以使用锚点 (<a>
) 标签链接到不同的页面。当用户单击链接时,URL 会被推送到浏览器历史记录堆栈中。当用户按下后退按钮时,浏览器会从历史堆栈顶部弹出该项目,因此活动页面现在是以前访问过的页面。React Native 不像 Web 浏览器那样具有全局历史堆栈的内置概念 - 这就是 React Navigation 的用武之地。
¥In a web browser, you can link to different pages using an anchor (<a>
) tag. When the user clicks on a link, the URL is pushed to the browser history stack. When the user presses the back button, the browser pops the item from the top of the history stack, so the active page is now the previously visited page. React Native doesn't have a built-in idea of a global history stack like a web browser does -- this is where React Navigation enters the story.
React Navigation 的原生堆栈导航器为你的应用提供了一种在屏幕之间转换和管理导航历史记录的方法。如果你的应用仅使用一个堆栈导航器,那么它在概念上类似于网络浏览器处理导航状态的方式 - 当用户与应用交互时,你的应用会从导航堆栈中推送和弹出项目,这会导致用户看到不同的屏幕。在 Web 浏览器和 React Navigation 中的工作方式之间的一个关键区别在于,React Navigation 的原生堆栈导航器提供了你在 Android 和 iOS 上在堆栈中的路由之间导航时所期望的手势和动画。
¥React Navigation's native stack navigator provides a way for your app to transition between screens and manage navigation history. If your app uses only one stack navigator then it is conceptually similar to how a web browser handles navigation state - your app pushes and pops items from the navigation stack as users interact with it, and this results in the user seeing different screens. A key difference between how this works in a web browser and in React Navigation is that React Navigation's native stack navigator provides the gestures and animations that you would expect on Android and iOS when navigating between routes in the stack.
我们先来演示一下最常见的导航器 createNativeStackNavigator
。
¥Let's start by demonstrating the most common navigator, createNativeStackNavigator
.
安装原生堆栈导航器库
¥Installing the native stack navigator library
到目前为止,我们安装的库是导航器的构建块和共享基础,React Navigation 中的每个导航器都位于自己的库中。要使用原生堆栈导航器,我们需要安装 @react-navigation/native-stack
:
¥The libraries we've installed so far are the building blocks and shared foundations for navigators, and each navigator in React Navigation lives in its own library. To use the native stack navigator, we need to install @react-navigation/native-stack
:
- npm
- Yarn
- pnpm
npm install @react-navigation/native-stack
yarn add @react-navigation/native-stack
pnpm add @react-navigation/native-stack
@react-navigation/native-stack
依赖于 react-native-screens
以及我们在 入门 中安装的其他库。如果你还没有安装这些,请转到该页面并按照安装说明进行操作。
¥@react-navigation/native-stack
depends on react-native-screens
and the other libraries that we installed in Getting started. If you haven't installed those yet, head over to that page and follow the installation instructions.
安装元素库
¥Installing the elements library
@react-navigation/elements
库提供了一组旨在与 React Navigation 配合良好的组件。我们将在本指南中使用其中一些组件。因此,让我们先安装它:
¥The @react-navigation/elements
library provides a set of components that are designed to work well with React Navigation. We'll use a few of these components in this guide. So let's install it first:
- npm
- Yarn
- pnpm
npm install @react-navigation/elements
yarn add @react-navigation/elements
pnpm add @react-navigation/elements
创建原生堆栈导航器
¥Creating a native stack navigator
- Static
- Dynamic
createNativeStackNavigator
是一个函数,它采用包含屏幕和自定义选项的配置对象。屏幕是渲染导航器显示的内容的 React 组件。
¥createNativeStackNavigator
is a function that takes a configuration object containing the screens and customization options. The screens are React Components that render the content displayed by the navigator.
createStaticNavigation
是一个函数,它接受先前定义的导航器并返回一个可以在应用中渲染的组件。它在应用中仅调用一次。
¥createStaticNavigation
is a function that takes the navigator defined earlier and returns a component that can be rendered in the app. It's only called once in the app.
// In App.js in a new project
import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const RootStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
},
});
const Navigation = createStaticNavigation(RootStack);
export default function App() {
return <Navigation />;
}
createNativeStackNavigator
是一个返回包含 2 个属性的对象的函数:Screen
和 Navigator
。它们都是用于配置导航器的 React 组件。Navigator
应包含 Screen
元素作为其子元素来定义路由的配置。
¥createNativeStackNavigator
is a function that returns an object containing 2 properties: Screen
and Navigator
. Both of them are React components used for configuring the navigator. The Navigator
should contain Screen
elements as its children to define the configuration for routes.
NavigationContainer
是一个管理我们的导航树并包含 导航状态 的组件。此组件必须封装应用中的所有导航器。通常,我们会在应用的根目录渲染此组件,该组件通常是从 App.js
导出的组件。
¥NavigationContainer
is a component that manages our navigation tree and contains the navigation state. This component must wrap all the navigators in the app. Usually, we'd render this component at the root of our app, which is usually the component exported from 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 { createNativeStackNavigator } from '@react-navigation/native-stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
function RootStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<RootStack />
</NavigationContainer>
);
}
如果运行此代码,你将看到一个屏幕,其中有一个空的导航栏和一个包含 HomeScreen
组件的灰色内容区域(如上所示)。你看到的导航栏和内容区域的样式是堆栈导航器的默认配置,我们稍后将学习如何配置它们。
¥If you run this code, you will see a screen with an empty navigation bar and a grey content area containing your HomeScreen
component (shown above). The styles you see for the navigation bar and the content area are the default configuration for a stack navigator, we'll learn how to configure those later.
路由名称的大小写并不重要 - 你可以使用小写 home
或大写 Home
,这取决于你。我们更喜欢将路由名称大写。
¥The casing of the route name doesn't matter -- you can use lowercase home
or capitalized Home
, it's up to you. We prefer capitalizing our route names.
配置导航器
¥Configuring the navigator
所有的路由配置都被指定为我们的导航器的属性。我们没有向导航器传递任何属性,因此它只使用默认配置。
¥All of the route configuration is specified as props to our navigator. We haven't passed any props to our navigator, so it just uses the default configuration.
让我们向原生堆栈导航器添加第二个屏幕,并将 Home
屏幕配置为首先渲染:
¥Let's add a second screen to our native stack navigator and configure the Home
screen to render first:
- Static
- Dynamic
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
Home: HomeScreen,
Details: DetailsScreen,
},
});
现在我们的堆栈有两条路由,一条 Home
路由和一条 Details
路由。可以在 screens
属性下指定路由。screens
下的属性名称对应于我们将用于导航的路由名称,值对应于它将渲染的组件。
¥Now our stack has two routes, a Home
route and a Details
route. A route can be specified by under the screens
property. The name of the property under screens
corresponds to the name of the route we will use to navigate, and the value corresponds to the component it'll render.
function RootStack() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
现在我们的堆栈有两条路由,一条 Home
路由和一条 Details
路由。可以使用 Screen
组件指定路由。Screen
组件接受一个 name
属性,它对应于我们将用于导航的路由的名称,以及一个 component
属性,它对应于它将渲染的组件。
¥Now our stack has two routes, a Home
route and a Details
route. A route can be specified by using the Screen
component. The Screen
component accepts a name
prop which corresponds to the name of the route we will use to navigate, and a component
prop which corresponds to the component it'll render.
使用动态 API 时,component
prop 接受组件,而不是渲染函数。不要传递内联函数(例如 component={() => <HomeScreen />}
),否则当父组件重新渲染时,你的组件将卸载并重新安装,从而丢失所有状态。请参阅 传递额外的属性 了解替代方案。
¥When using the dynamic API, the component
prop accepts a component, not a render function. Don't pass an inline function (e.g. component={() => <HomeScreen />}
), or your component will unmount and remount losing all state when the parent component re-renders. See Passing additional props for alternatives.
这里,Home
路由对应于 HomeScreen
组件,Details
路由对应于 DetailsScreen
组件。堆栈的初始路由是 Home
路由。尝试将其更改为 Details
并重新加载应用(React Native 的快速刷新不会更新 initialRouteName
的更改,如你所料),请注意,你现在将看到 Details
屏幕。然后将其更改回 Home
并再次重新加载。
¥Here, the Home
route corresponds to the HomeScreen
component, and the Details
route corresponds to the DetailsScreen
component. The initial route for the stack is the Home
route. Try changing it to Details
and reload the app (React Native's Fast Refresh won't update changes from initialRouteName
, as you might expect), notice that you will now see the Details
screen. Then change it back to Home
and reload once more.
指定选项
¥Specifying options
导航器中的每个屏幕都可以为导航器指定一些选项,例如要在标题中渲染的标题。
¥Each screen in the navigator can specify some options for the navigator, such as the title to render in the header.
- Static
- Dynamic
要指定选项,我们将更改指定屏幕组件的方式。除了将屏幕组件指定为值之外,我们还可以指定具有 screen
属性的对象:
¥To specify the options, we'll change how we have specified the screen component. Instead of specifying the screen component as the value, we can also specify an object with a screen
property:
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
Home: {
screen: HomeScreen,
},
Details: DetailsScreen,
},
});
这将让我们为屏幕指定其他选项。
¥This will let us specify additional options for the screen.
现在,我们可以添加 options
属性:
¥Now, we can add an options
property:
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
Home: {
screen: HomeScreen,
options: {
title: 'Overview',
},
},
Details: DetailsScreen,
},
});
有时我们希望为导航器中的所有屏幕指定相同的选项。为此,我们可以在配置中添加一个 screenOptions
属性:
¥Sometimes we will want to specify the same options for all of the screens in the navigator. For that, we can add a screenOptions
property to the configuration:
const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screenOptions: {
headerStyle: { backgroundColor: 'tomato' },
},
screens: {
Home: {
screen: HomeScreen,
options: {
title: 'Overview',
},
},
Details: DetailsScreen,
},
});
可以在每个屏幕组件的 options
prop 中传递任何自定义选项:
¥Any customization options can be passed in the options
prop for each screen component:
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Overview' }}
/>
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
有时我们希望为导航器中的所有屏幕指定相同的选项。为此,我们可以将一个 screenOptions
属性传递给导航器:
¥Sometimes we will want to specify the same options for all of the screens in the navigator. For that, we can pass a screenOptions
prop to the navigator:
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerStyle: { backgroundColor: 'tomato' },
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Overview' }}
/>
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
传递额外的属性
¥Passing additional props
- Static
- Dynamic
静态 API 不支持将其他属性传递给屏幕。
¥Passing additional props to a screen is not supported in the static API.
有时我们可能想将额外的属性传递到屏幕。我们可以通过两种方法来做到这一点:
¥Sometimes we might want to pass additional props to a screen. We can do that with 2 approaches:
-
使用 React 上下文 并使用上下文提供程序封装导航器以将数据传递到屏幕(推荐)。
¥Use React context and wrap the navigator with a context provider to pass data to the screens (recommended).
-
使用屏幕的渲染回调而不是指定
component
属性:¥Use a render callback for the screen instead of specifying a
component
prop:<Stack.Screen name="Home">
{(props) => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
默认情况下,React Navigation 会对屏幕组件进行优化,以防止不必要的渲染。使用渲染回调可以消除这些优化。因此,如果你使用渲染回调,则需要确保对屏幕组件使用 React.memo
或 React.PureComponent
以避免出现性能问题。
¥By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you use React.memo
or React.PureComponent
for your screen components to avoid performance issues.
下一步是什么?
¥What's next?
此时自然的问题是:“如何从 Home
路由转到 Details
路由?”。下一节 中对此进行了介绍。
¥The natural question at this point is: "how do I go from the Home
route to the Details
route?". That is covered in the next section.
Using with TypeScript
如果你使用 TypeScript,则需要相应地指定类型。你可以在了解基础知识后查看 使用 TypeScript 进行类型检查 以了解更多详细信息。目前,我们不会在示例中介绍 TypeScript。
¥If you are using TypeScript, you will need to specify the types accordingly. You can check Type checking with TypeScript after going through the fundamentals for more details. For now, we won't be covering TypeScript in the examples.
概括
¥Summary
- Static
- Dynamic
-
React Native 没有像 Web 浏览器那样的内置导航 API。React Navigation 为你提供了这一点,以及用于在屏幕之间转换的 iOS 和 Android 手势和动画。
¥React Native doesn't have a built-in API for navigation like a web browser does. React Navigation provides this for you, along with the iOS and Android gestures and animations to transition between screens.
-
createNativeStackNavigator
是一个函数,它接受屏幕配置并渲染我们的内容。¥
createNativeStackNavigator
is a function that takes the screens configuration and renders our content. -
屏幕下的每个属性都指的是路由的名称,值是要为路由渲染的组件。
¥Each property under screens refers to the name of the route, and the value is the component to render for the route.
-
要指定堆栈中的初始路由,请为导航器提供
initialRouteName
选项。¥To specify what the initial route in a stack is, provide an
initialRouteName
option for the navigator. -
要指定特定于屏幕的选项,我们可以指定
options
属性,对于通用选项,我们可以指定screenOptions
。¥To specify screen-specific options, we can specify an
options
property, and for common options, we can specifyscreenOptions
.
-
React Native 没有像 Web 浏览器那样的内置导航 API。React Navigation 为你提供了这一点,以及用于在屏幕之间转换的 iOS 和 Android 手势和动画。
¥React Native doesn't have a built-in API for navigation like a web browser does. React Navigation provides this for you, along with the iOS and Android gestures and animations to transition between screens.
-
Stack.Navigator
是一个组件,它将路由配置作为其子组件,并具有用于配置的附加属性并渲染我们的内容。¥
Stack.Navigator
is a component that takes route configuration as its children with additional props for configuration and renders our content. -
每个
Stack.Screen
组件都采用name
属性(指的是路由名称)和component
属性(指定要为路由渲染的组件)。这是 2 个必需的属性。¥Each
Stack.Screen
component takes aname
prop which refers to the name of the route andcomponent
prop which specifies the component to render for the route. These are the 2 required props. -
要指定堆栈中的初始路由是什么,请提供
initialRouteName
作为导航器的 prop。¥To specify what the initial route in a stack is, provide an
initialRouteName
as the prop for the navigator. -
要指定特定于屏幕的选项,我们可以将
options
属性传递给Stack.Screen
,对于通用选项,我们可以将screenOptions
传递给Stack.Navigator
。¥To specify screen-specific options, we can pass an
options
prop toStack.Screen
, and for common options, we can passscreenOptions
toStack.Navigator
.