首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

React Native 导航和路由

基础知识

1. React Native 中导航的作用是什么?

1. 页面切换与状态管理

React Native 中的导航组件(如 React Navigation 或 React Native Navigation)可以帮助开发者实现多个屏幕之间的切换,例如从列表页面跳转到详情页面。

它会自动处理页面的堆栈管理(Stack),记录用户的访问历史,支持前进和后退操作。

2. 提高用户体验

提供动画效果(如页面推入、淡入淡出等),让页面切换更加流畅自然。

支持手势操作,例如从屏幕边缘滑动返回上一页。

3. 参数传递与页面通信

导航可以在页面之间传递参数。例如,在一个产品列表页面点击某个商品后,导航到详情页面时传递商品的 ID。

Route 和 Params 的配合可以让页面获取上下文信息。

4. 导航类型支持

支持多种导航类型:

栈式导航(Stack Navigator):模拟页面堆栈,按顺序推入或弹出页面。

底部标签导航(Bottom Tab Navigator):常用于应用主界面,提供不同功能的快速切换。

抽屉导航(Drawer Navigator):从屏幕侧边滑出菜单,适合显示附加功能。

嵌套导航:可以组合多种导航方式以满足复杂的应用需求。

5. 跨平台一致性

React Native 的导航解决方案可以在 iOS 和 Android 平台上提供一致的体验,同时支持平台特定的导航行为。

6. 可扩展性

提供钩子(如 useNavigation)和生命周期事件,方便开发者在导航过程中处理额外的逻辑,例如数据加载、权限检查等。

支持动态配置标题栏、按钮等 UI 元素。

2. React Native 中有哪些常用的导航库?它们的优缺点分别是什么?

在 React Native 中,常用的导航库主要有以下几个,每个库都具有各自的特点、优点和缺点,适用于不同的场景:

1. React Navigation

这是最常用的导航库之一,由社区主导开发,功能强大且灵活。

优点:

灵活性高:支持多种导航模式(栈导航、标签导航、抽屉导航等),且支持嵌套导航。

社区活跃:拥有广泛的文档、教程和社区支持。

跨平台一致性:在 iOS 和 Android 上表现一致。

高度可定制:可配置导航栏样式、动画、手势等。

支持动态功能:如动态标题、参数传递等。

缺点:

性能较低:使用 JavaScript 实现导航,在复杂场景下性能可能不如原生导航库。

配置复杂:功能多样化导致配置代码相对繁琐。

适用场景:

需要跨平台一致性且不要求极致性能的应用。

项目复杂度较高,需要多种导航模式。

2. React Native Navigation

由 Wix 开发,采用原生实现导航,性能表现优异。

优点:

性能优秀:使用原生代码实现导航,页面切换流畅。

原生外观:与平台原生导航行为完全一致。

支持复杂场景:能轻松实现复杂的嵌套导航和动态功能。

缺点:

学习成本较高:配置较复杂,需要了解更多的原生开发知识。

灵活性较低:自定义程度不如 React Navigation,但能满足大部分需求。

社区支持较弱:相比 React Navigation,文档和社区资源相对较少。

适用场景:

高性能要求的应用(如需要快速页面切换的复杂应用)。

对原生外观和行为要求较高的应用。

3. React Native Router Flux

基于 React Navigation 的封装,提供更简洁的 API。

优点:

API 简单:对 React Navigation 进行了封装,简化了导航配置。

快速上手:适合初学者或需要快速实现导航功能的项目。

缺点:

不够灵活:对 React Navigation 的封装限制了部分高级功能的使用。

更新较慢:与 React Navigation 的版本更新存在一定的滞后性。

适用场景:

简单的项目或初学者使用。

不需要复杂导航逻辑的应用。

4. Native Stack Navigator

React Navigation 提供的性能优化选项,使用原生组件实现栈导航。

优点:

性能更好:与 React Navigation 的 JavaScript 栈导航相比,速度更快。

使用方便:仍然遵循 React Navigation 的 API 和生态。

缺点:

功能有限:只适用于栈导航场景,灵活性较低。

适用场景:

只需要栈导航,且对性能要求较高的应用。

5. Expo Router

基于 React Navigation,采用文件系统路由的导航方案(类似 Next.js)。

优点:

文件路由系统:通过文件夹结构定义导航路径,直观且易维护。

集成度高:适用于 Expo 项目,配置简单。

缺点:

适用范围有限:对非 Expo 项目支持较差。

灵活性较低:某些复杂场景可能不如手动配置导航灵活。

适用场景:

使用 Expo 构建的项目,且追求快速开发。

总结对比:

3. 如何在 React Native 中实现路由跳转?

在 React Native 中,实现路由跳转通常需要使用导航库(如 React Navigation)。以下是一个完整的实现过程,包括设置导航器和实现页面跳转的步骤。

1. 安装 React Navigation 和相关依赖

运行以下命令安装 React Navigation 和必需的依赖:

# 安装核心库

npm install @react-navigation/native

# 安装导航器所需依赖

npm install react-native-screens react-native-safe-area-context react-native-gesture-handler react-native-reanimated react-native-vector-icons

# 安装栈导航

npm install @react-navigation/stack

确保在项目的 index.js 文件中添加以下代码(仅需一次配置):

import 'react-native-gesture-handler';

2. 设置导航容器

创建一个导航容器并配置路由。以下以 栈导航(Stack Navigator) 为例:

创建 App.js 文件:

import React from 'react';

import { NavigationContainer } from '@react-navigation/native';

import { createStackNavigator } from '@react-navigation/stack';

import HomeScreen from './screens/HomeScreen';

import DetailsScreen from './screens/DetailsScreen';

const Stack = createStackNavigator();

export default function App() {

return (

<NavigationContainer>

<Stack.Navigator initialRouteName="Home">

<Stack.Screen name="Home" component={HomeScreen} />

<Stack.Screen name="Details" component={DetailsScreen} />

</Stack.Navigator>

</NavigationContainer>

);

}

3. 创建页面组件

创建 HomeScreen.js:

import React from 'react';

import { View, Text, Button, StyleSheet } from 'react-native';

const HomeScreen = ({ navigation }) => {

return (

<View style={styles.container}>

<Text style={styles.title}>Home Screen</Text>

<Button

title="Go to Details"

onPress={() => navigation.navigate('Details', { itemId: 42 })}

/>

</View>

);

};

const styles = StyleSheet.create({

container: {

flex: 1,

justifyContent: 'center',

alignItems: 'center',

},

title: {

fontSize: 24,

fontWeight: 'bold',

},

});

export default HomeScreen;

创建 DetailsScreen.js:

import React from 'react';

import { View, Text, Button, StyleSheet } from 'react-native';

const DetailsScreen = ({ route, navigation }) => {

const { itemId } = route.params || {};

return (

<View style={styles.container}>

<Text style={styles.title}>Details Screen</Text>

<Text>Item ID: {itemId}</Text>

<Button title="Go Back" onPress={() => navigation.goBack()} />

</View>

);

};

const styles = StyleSheet.create({

container: {

flex: 1,

justifyContent: 'center',

alignItems: 'center',

},

title: {

fontSize: 24,

fontWeight: 'bold',

},

});

export default DetailsScreen;

4. 路由跳转的实现

常用的导航方法:

navigation.navigate(name, params)

跳转到指定页面,可传递参数。

示例:

navigation.navigate('Details', { itemId: 42 });

navigation.goBack()

返回上一页。

示例:

navigation.goBack();

navigation.push(name, params)

将指定页面推入栈中,即使当前页面已经是目标页面,也会再次创建。

示例:

navigation.push('Details', { itemId: 100 });

navigation.replace(name, params)

替换当前页面,不会保留返回历史。

示例:

navigation.replace('Home');

navigation.popToTop()

返回到栈顶页面。

示例:

navigation.popToTop();

5. 接收路由参数

在目标页面中,通过 route.params 接收路由参数。例如:

const DetailsScreen = ({ route }) => {

const { itemId } = route.params || {};

return <Text>Item ID: {itemId}</Text>;

};

6. 自定义页面标题

可以通过 options 自定义页面标题:

<Stack.Screen

name="Details"

component={DetailsScreen}

options={{ title: 'Detail Page' }}

/>

也可以在页面组件中动态设置标题:

React.useLayoutEffect(() => {

navigation.setOptions({ title: 'Custom Title' });

}, [navigation]);

完整示例代码结构

App.js

screens/

- HomeScreen.js

- DetailsScreen.js

4. 什么是堆栈(Stack)、选项卡(Tab)和抽屉(Drawer)导航?它们的使用场景有哪些?

在 React Native 中,堆栈(Stack)、选项卡(Tab)、和抽屉(Drawer)导航是最常见的三种导航模式,每种都有其特点和适用场景:

1. 堆栈导航(Stack Navigation)

定义:

堆栈导航模拟了浏览器的导航历史或页面栈的行为。用户可以通过“压入”新页面进入下一级页面,或通过“弹出”返回上一级页面。

特点:

具有“前进”和“返回”的功能,常用于页面之间的线性跳转。

每次导航会将新页面加入到堆栈顶部(类似函数调用栈)。

典型页面切换动画(如从右侧滑入、从左侧滑出)。

使用场景:

页面之间有明确的层级关系,例如:

列表页跳转到详情页。

登录页跳转到主页面。

用户可能需要返回到之前的页面。

代码示例:

import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

<Stack.Screen name="Home" component={HomeScreen} />

<Stack.Screen name="Details" component={DetailsScreen} />

2. 选项卡导航(Tab Navigation)

定义:

选项卡导航通过底部或顶部的标签(Tab)切换页面,每个标签对应一个页面。标签导航通常显示多个并列的功能或页面。

特点:

页面的切换不会影响其他页面的状态(页面保持加载状态)。

用户可快速在不同页面间切换。

支持图标和文本标签,常见于底部导航栏。

使用场景:

应用有多个主要功能模块,用户需要频繁在模块之间切换,例如:

电商应用的“首页”、“分类”、“购物车”、“我的”。

社交应用的“消息”、“好友”、“动态”、“设置”。

代码示例:

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

<Tab.Screen name="Home" component={HomeScreen} />

<Tab.Screen name="Profile" component={ProfileScreen} />

3. 抽屉导航(Drawer Navigation)

定义:

抽屉导航是一种从屏幕边缘滑出侧边菜单的导航方式,菜单中列出不同页面的导航项。

特点:

左滑或点击菜单按钮时,侧边栏会滑出显示菜单。

适合页面功能较多但标签不适合显示在屏幕上的情况。

菜单可以包含嵌套导航。

使用场景:

应用需要提供较多的功能页面,但用户不需要频繁切换,例如:

设置页面。

企业管理系统的功能模块导航。

需要在一个主页面的基础上提供附加功能,例如:

地图应用的“图层选择”、“导航模式”。

代码示例:

import { createDrawerNavigator } from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

<Drawer.Screen name="Home" component={HomeScreen} />

<Drawer.Screen name="Settings" component={SettingsScreen} />

导航模式对比与选择

综合场景

在复杂应用中,可能需要结合使用这些导航模式。例如:

电商应用:

底部选项卡:显示主要功能模块(首页、分类、购物车、我的)。

堆栈导航:从列表页跳转到详情页,或从购物车跳转到结算页面。

抽屉导航:从侧边打开“帮助中心”、“关于我们”等功能。

导航行为

1. 如何在导航中监听路由变化?

在 React Native 中,监听路由变化通常需要借助 React Navigation 提供的钩子或事件订阅机制。这可以帮助开发者在页面切换时执行特定的逻辑,如统计分析、更新状态或触发动画。

方法 1:使用 useFocusEffect 钩子

useFocusEffect 是 React Navigation 提供的一个钩子,专门用于处理页面聚焦时的逻辑。

示例代码:

import React from 'react';

import { View, Text } from 'react-native';

import { useFocusEffect } from '@react-navigation/native';

const HomeScreen = () => {

useFocusEffect(

React.useCallback(() => {

console.log('HomeScreen is focused');

return () => {

console.log('HomeScreen is unfocused');

};

}, [])

);

return (

<View>

<Text>Home Screen</Text>

</View>

);

};

export default HomeScreen;

特点:

在页面被导航至时触发逻辑。

返回一个清理函数,当页面离开焦点时触发。

方法 2:使用 useNavigationState 钩子

useNavigationState 钩子允许你访问导航器的状态,可以用来监控路由变化。

示例代码:

import React from 'react';

import { View, Text } from 'react-native';

import { useNavigationState } from '@react-navigation/native';

const HomeScreen = () => {

const state = useNavigationState(state => state);

React.useEffect(() => {

console.log('Current route name:', state.routes[state.index].name);

}, [state]);

return (

<View>

<Text>Home Screen</Text>

</View>

);

};

export default HomeScreen;

特点:

获取当前导航栈的状态。

可以判断当前活跃的路由。

方法 3:使用 addListener 订阅事件

通过 navigation.addListener 可以监听导航事件,例如 focus 和 blur。

示例代码:

import React, { useEffect } from 'react';

import { View, Text } from 'react-native';

const HomeScreen = ({ navigation }) => {

useEffect(() => {

const unsubscribeFocus = navigation.addListener('focus', () => {

console.log('HomeScreen is focused');

});

const unsubscribeBlur = navigation.addListener('blur', () => {

console.log('HomeScreen is unfocused');

});

return () => {

unsubscribeFocus();

unsubscribeBlur();

};

}, [navigation]);

return (

<View>

<Text>Home Screen</Text>

</View>

);

};

export default HomeScreen;

特点:

事件可以单独订阅和清理。

适用于类组件和函数组件。

方法 4:使用全局 onStateChange

NavigationContainer 提供了 onStateChange 属性,可以在导航器状态发生变化时触发全局监听。

示例代码:

import React from 'react';

import { NavigationContainer } from '@react-navigation/native';

import { createStackNavigator } from '@react-navigation/stack';

import HomeScreen from './screens/HomeScreen';

import DetailsScreen from './screens/DetailsScreen';

const Stack = createStackNavigator();

const App = () => {

return (

<NavigationContainer

onStateChange={(state) => {

const currentRoute = state.routes[state.index];

console.log('Current route:', currentRoute.name);

}}

>

<Stack.Navigator initialRouteName="Home">

<Stack.Screen name="Home" component={HomeScreen} />

<Stack.Screen name="Details" component={DetailsScreen} />

</Stack.Navigator>

</NavigationContainer>

);

};

export default App;

特点:

全局监听导航状态变化。

不需要在每个页面单独设置监听。

方法 5:使用 useRoute 钩子获取当前路由

通过 useRoute 可以获取当前路由对象,但不会自动监听变化。需要结合 useEffect 来实现逻辑。

示例代码:

import React, { useEffect } from 'react';

import { View, Text } from 'react-native';

import { useRoute } from '@react-navigation/native';

const HomeScreen = () => {

const route = useRoute();

useEffect(() => {

console.log('Route params:', route.params);

}, [route.params]);

return (

<View>

<Text>Home Screen</Text>

</View>

);

};

export default HomeScreen;

特点:

适合监听路由参数的变化。

不适合全局路由监听。

总结

2. 如何禁用或自定义返回行为?

以下是几种常见的禁用或自定义返回行为的方法:

1. 使用 navigation.goBack() 来自定义返回行为

如果你希望在某个页面按下返回按钮时执行自定义操作,而不是直接返回上一个页面,可以使用 navigation.goBack() 结合条件来决定是否执行返回行为。

示例代码:

import React from 'react';

import { Button, Alert, View } from 'react-native';

const DetailsScreen = ({ navigation }) => {

const handleGoBack = () => {

// 可以在这里自定义逻辑,例如确认返回或执行其他操作

Alert.alert(

"Confirm",

"Do you really want to go back?",

[

{ text: "Cancel", style: "cancel" },

{ text: "Yes", onPress: () => navigation.goBack() }

]

);

};

return (

<View>

<Button title="Go Back" onPress={handleGoBack} />

</View>

);

};

export default DetailsScreen;

特点:

通过自定义事件来控制返回行为。

可以实现弹出确认框或执行额外逻辑。

2. 使用 navigation.pop() 来控制返回行为

如果你想跳过多个页面返回,可以使用 pop() 来指定返回到特定的页面,而不是简单地返回到上一个页面。

示例代码:

const handleGoBack = () => {

// 返回到距离当前页面两层的页面

navigation.pop(2);

};

3. 禁用物理返回按钮(Android)

在 Android 中,用户可以通过设备的物理返回按钮返回上一个页面。如果你想禁用这个按钮,可以使用 BackHandler 来拦截物理返回按钮的事件。

示例代码:

import React, { useEffect } from 'react';

import { BackHandler, Alert, View } from 'react-native';

const DetailsScreen = () => {

useEffect(() => {

const backAction = () => {

Alert.alert("Hold on!", "Are you sure you want to exit?", [

{

text: "Cancel",

onPress: () => null,

style: "cancel"

},

{ text: "YES", onPress: () => BackHandler.exitApp() }

]);

return true; // 返回 `true` 来拦截默认返回行为

};

const backHandler = BackHandler.addEventListener(

"hardwareBackPress",

backAction

);

// 清理事件监听器

return () => backHandler.remove();

}, []);

return <View>{/* 页面内容 */}</View>;

};

export default DetailsScreen;

特点:

你可以根据需要显示确认对话框来确定是否退出或禁用返回。

在组件卸载时清理事件监听器。

4. 使用 useFocusEffect 来控制返回行为

如果你希望根据页面的聚焦状态自定义返回行为,可以使用 useFocusEffect 钩子来监听页面是否被聚焦,并在聚焦时禁用返回按钮或进行其他操作。

示例代码:

import React, { useEffect } from 'react';

import { BackHandler, Alert, View } from 'react-native';

import { useFocusEffect } from '@react-navigation/native';

const DetailsScreen = () => {

useFocusEffect(

React.useCallback(() => {

const backAction = () => {

Alert.alert("Hold on!", "Are you sure you want to exit?", [

{ text: "Cancel", style: "cancel" },

{ text: "YES", onPress: () => BackHandler.exitApp() }

]);

return true; // 拦截返回事件

};

const backHandler = BackHandler.addEventListener(

"hardwareBackPress",

backAction

);

// 清理事件监听器

return () => backHandler.remove();

}, [])

);

return <View>{/* 页面内容 */}</View>;

};

export default DetailsScreen;

特点:

通过 useFocusEffect 可以监听页面的聚焦状态,自定义聚焦时的返回行为。

适合根据页面状态动态启用或禁用返回按钮。

5. 使用 createStackNavigator 中的 gestureEnabled 属性来禁用滑动返回

如果你希望禁用页面的滑动返回(例如在 iOS 中的滑动返回),可以在 createStackNavigator 中设置 gestureEnabled: false。

示例代码:

import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

const App = () => {

return (

<Stack.Navigator screenOptions={{ gestureEnabled: false }}>

<Stack.Screen name="Home" component={HomeScreen} />

<Stack.Screen name="Details" component={DetailsScreen} />

</Stack.Navigator>

);

};

export default App;

特点:

禁用 iOS 中的滑动返回手势。

适用于需要完全自定义导航行为的场景。

总结

自定义返回行为:

使用 navigation.goBack() 或 navigation.pop() 来自定义返回逻辑。

结合条件判断和用户交互来控制返回行为。

禁用物理返回按钮:

使用 BackHandler 拦截并自定义物理返回按钮的行为。

禁用滑动返回手势:

使用 gestureEnabled: false 禁用滑动返回手势(适用于 iOS)。

3. React Navigation 如何处理深度链接(Deep Linking)?

在 React Native 中,React Navigation 提供了对深度链接(Deep Linking)的支持,使得应用能够响应外部URL,并将用户导航到特定的屏幕或内容。深度链接通常用于处理外部应用、网页或通知中的链接,直接引导用户到应用中的特定页面。

React Navigation 中深度链接的配置和处理

React Navigation 的深度链接处理主要依赖于以下几个步骤:

1. 配置深度链接的目标 URL 格式

首先,你需要定义一个 URL 模式,这个模式描述了应用的深度链接的结构。可以通过在导航容器(NavigationContainer)中配置 linking 属性来设置深度链接的处理规则。

基本配置

假设我们有一个应用,其中包含主页(Home)和详情页(Details)。你可以这样配置深度链接:

解释:

prefixes:指定支持的 URL 协议,例如 myapp://,表示只有以 myapp:// 开头的 URL 才会触发应用的导航。

2. 处理 URL 中的参数

示例:3. 处理 iOS 和 Android 的深度链接

在 React Native 中,除了在 React Navigation 中配置深度链接,你还需要在原生部分进行配置。对于 iOS 和 Android,它们的深度链接处理方式稍有不同。

iOS 配置

添加以下配置:

<dict>

<key>CFBundleURLSchemes</key>

<array>

<string>myapp</string> <!-- 配置协议 -->

</array>

</dict>

Android 配置

在 Android 中,你需要在 AndroidManifest.xml 中注册 URL 协议:

添加以下内容:

4. 监听 URL 和更新导航状态

React Navigation 在应用打开时会自动解析深度链接,并将用户导航到对应的页面。如果你需要监听 URL 的变化,可以使用 Linking API 来处理。

监听深度链接事件:

import { Linking, useLinking } from '@react-navigation/native';

useEffect(() => {

const handleDeepLink = (event) => {

console.log(event.url); // 输出当前的 URL

};

// 监听 deep link 事件

Linking.addEventListener('url', handleDeepLink);

// 清理事件监听器

return () => {

Linking.removeEventListener('url', handleDeepLink);

};

}, []);

5. 使用深度链接打开特定页面

总结

下文预告

《React Native 性能优化》

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OOxHEbQtF5JBCFMTLn--LjMw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券