在 Web 浏览器中,您可以使用锚标记链接到不同的页面。当用户单击链接时,URL 会被推送到浏览器历史记录堆栈
中。当用户按下后退按钮时,浏览器会从历史堆栈顶部弹出该项目,因此活动页面现在是以前访问过的页面。React Native 不像 Web 浏览器那样具有全局历史堆栈的内置概念,而 React Navigation 就是帮助我们实现导航管理的工具。
React Navigation 的堆栈导航器为您的应用程序提供了一种在屏幕之间转换和管理导航历史记录的方法。如果您的应用程序仅使用一个堆栈导航器,那么它在概念上类似于 Web 浏览器处理导航状态的方式 - 当用户与其交互时,您的应用程序会从导航堆栈中推送和弹出项目,这会导致用户看到不同的屏幕。React Navigation 的堆栈导航器提供了您在 Android 和 iOS 上在堆栈中的路由之间导航时所期望的手势和动画。
安装堆栈导航器
在上一篇文章中,我们安装了导航器的构建模块和基础模块,当我们需要堆栈导航器的话则需要安装如下包:
shell
npm install @react-navigation/native-stack
创建堆栈
首先我们先来看一个简单的实例:
typescript
import React from "react";
import Home from "./page/Home";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
const App: React.FC = () => {
const Stack = createNativeStackNavigator();
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home Page" component={Home} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
运行后效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDUJWkBl-1693035587956)(./images/ReactNavigation.png "ReactNavigation1")]
从上述的例子我们可以看到我们使用了一个createNativeStackNavigator()
方法来创建导航堆栈。createNativeStackNavigator
是一个返回包含 2 个属性的对象的函数:Screen
和 Navigator
。它们都是用于配置导航器的 React 组件。应该 Navigator 包含 Screen 元素作为其子元素来定义路由的配置。
NavigationContainer
是管理导航树并包含导航状态的组件。该组件必须包装所有导航器结构。通常,我们会在应用程序的根目录渲染此组件,这通常是从 App.tsx 中进行绑定。
配置第二条导航路线
在上述的代码基础上改为如下代码:
typescript
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
现在我们的堆栈有两条路线,一条 Home 路线和一条 Details 路线。可以使用组件来指定路线 Screen。该 Screen 组件接受一个 name 与我们将用于导航的路线名称相对应的 prop,以及一个 component 与它将渲染的组件相对应的 prop。
现在路由导航中,Home 路由对应组件 Home,Details 路由对应组件 DetailsScreen。
注意:
Stack.Screen
组件中的component
接受组件,而不是渲染函数,不要传递内联函数(例如:component={() => <组件 />}),否则当父组件重新渲染时,您的组件将卸载并重新安装,从而丢失所有状态。请参阅传递额外的 props 以获取替代方案。
Stack.Screen 说明
Stack.Screen
组件除了name
和component
属性外,还可以使用options
来设置其他参数属性,具体实例如下:
typescript
<Stack.Navigator>
<Stack.Screen
name="Home Page"
component={Home}
options={{ title: "Overview" }}
/>
<Stack.Screen name="Detail Page" component={ReviewDetails} />
</Stack.Navigator>
有时候我们可能想将额外的参数传递给对应的组件,我们有如下两个方式来实现:
-
使用 React context 并使用 context 提供程序包装导航器以将数据传递到屏幕(推荐)
-
对屏幕使用渲染回调而不是指定 componentprop:
typescript<Stack.Screen name="Home"> {(props) => <HomeScreen {...props} extraData={someData} />} </Stack.Screen>
导航切换
首先我们举一个例子:
typescript
export default function Home(props: { navigation: any }) {
return (
<View>
<Text>Home</Text>
<Button
title="切换到详情页"
onPress={() => props.navigation.navigate("Detail Page")}
/>
</View>
);
}
实现上述代码后,我们点击按钮后页面会切换到详情页。接下来我们来说明一下具体的参数:
-
navigation
本机的堆栈导航器对象数据,并且每个组件都会带有此属性
-
navigate('Detail Page')
调用此函数可以帮我们把页面跳转到对应名称组件的页面
**注意:**如果我们在使用navigation.navigate
进行页面跳转的时候,跳转没有定义的路由时,开发环境下会报出对应的错误信息,但是打包的生产环境不会有任何反映。
路由循环
现在我们有两条路由,那么我们再进入详情页后,在重新导航到详情页那么会发生什么,我们用如下的代码实现验证一下:
typescript
export default function ReviewDetails(props: { navigation: any }) {
return (
<View>
<Text>ReviewDetails</Text>
<Button
title="切换到详情页"
onPress={() => props.navigation.navigate("Detail Page")}
/>
</View>
);
}
运行上述代码后,你会发现当点击切换到详情页
时,不会发生任何操作,并且点击返回后,我们可以直接一次性返回到首页。因为当我们在首页点击切换到详情页
后,我们的路由线路会跳转到详情页上,在当我们点击切换到详情页
时,程序会判断是否在详情页路由线上,假如在的话就不会做任何操作。
假设我们实际上想要添加一个新的详情页路由时,并且不管现有的导航历史记录如何的情况下,我们可以使用push
来实现。具体实例如下:
typescript
<View>
<Text>ReviewDetails</Text>
<Button
title="切换到详情页"
onPress={() => props.navigation.push("Detail Page")}
/>
</View>
每次您调用时,push 我们都会向导航堆栈添加一条新路线。当您 navigate 第一次调用它时,它会尝试查找具有该名称的现有路由,并且仅在堆栈上还没有路由时才推送新路由。
编程式导航
有时候我们可能会遇到头部导航没有返回按钮的情况,这时我们就可以使用goBack()
方法来实现返回上一级路由的功能,具体代码实例如下:
typescript
<Button title="返回上一页" onPress={() => props.navigation.goBack()}></Button>
还有就是我们想清除所有路由信息并返回第一个页面,具体代码如下:
typescript
<Button
title="清除所有堆栈信息返回首页"
onPress={() => props.navigation.popToTop()}
></Button>