React Native 导航和路由

824 阅读18分钟

基础知识

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

1. 页面切换与状态管理

  • React Native 中的导航组件(如 React NavigationReact Native Navigation)可以帮助开发者实现多个屏幕之间的切换,例如从列表页面跳转到详情页面。
  • 它会自动处理页面的堆栈管理(Stack),记录用户的访问历史,支持前进和后退操作。

2. 提高用户体验

  • 提供动画效果(如页面推入、淡入淡出等),让页面切换更加流畅自然。
  • 支持手势操作,例如从屏幕边缘滑动返回上一页。

3. 参数传递与页面通信

  • 导航可以在页面之间传递参数。例如,在一个产品列表页面点击某个商品后,导航到详情页面时传递商品的 ID。
  • RouteParams 的配合可以让页面获取上下文信息。

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 构建的项目,且追求快速开发。

总结对比:

导航库优点缺点适用场景
React Navigation灵活、社区活跃、多种导航模式性能稍差、配置复杂需要高灵活性的跨平台应用
React Native Navigation性能好、原生体验学习曲线陡峭、社区资源较少高性能、原生外观需求高
React Native Router Flux简单易用功能受限简单项目或初学者
Native Stack Navigator性能好、兼容 React Navigation 生态功能有限性能要求高的栈导航应用
Expo Router文件路由直观、集成方便灵活性低、适用范围有限使用 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. 路由跳转的实现

常用的导航方法:
  1. navigation.navigate(name, params)
    • 跳转到指定页面,可传递参数。
    • 示例:
navigation.navigate('Details', { itemId: 42 });
  1. navigation.goBack()
    • 返回上一页。
    • 示例:
navigation.goBack();
  1. navigation.push(name, params)
    • 将指定页面推入栈中,即使当前页面已经是目标页面,也会再次创建。
    • 示例:
navigation.push('Details', { itemId: 100 });
  1. navigation.replace(name, params)
    • 替换当前页面,不会保留返回历史。
    • 示例:
navigation.replace('Home');
  1. 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.Navigator>
  <Stack.Screen name="Home" component={HomeScreen} />
  <Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>

2. 选项卡导航(Tab Navigation)

定义:

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

特点:
  • 页面的切换不会影响其他页面的状态(页面保持加载状态)。
  • 用户可快速在不同页面间切换。
  • 支持图标和文本标签,常见于底部导航栏。
使用场景:
  • 应用有多个主要功能模块,用户需要频繁在模块之间切换,例如:
    • 电商应用的“首页”、“分类”、“购物车”、“我的”。
    • 社交应用的“消息”、“好友”、“动态”、“设置”。
代码示例:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

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

3. 抽屉导航(Drawer Navigation)

定义:

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

特点:
  • 左滑或点击菜单按钮时,侧边栏会滑出显示菜单。
  • 适合页面功能较多但标签不适合显示在屏幕上的情况。
  • 菜单可以包含嵌套导航。
使用场景:
  • 应用需要提供较多的功能页面,但用户不需要频繁切换,例如:
    • 设置页面。
    • 企业管理系统的功能模块导航。
  • 需要在一个主页面的基础上提供附加功能,例如:
    • 地图应用的“图层选择”、“导航模式”。
代码示例:
import { createDrawerNavigator } from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

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

导航模式对比与选择

导航模式特点适用场景
堆栈导航线性导航,支持页面的前进与返回,动画流畅。需要上下级页面跳转的应用,如列表到详情页、表单页面导航等。
选项卡导航并列导航,适合显示应用的主要功能模块,支持页面保持状态。需要用户频繁切换模块的应用,如社交、电商、新闻类应用的功能模块。
抽屉导航隐藏式菜单,适合功能较多但不常用的页面导航,菜单可以嵌套。功能丰富且主页面占用屏幕空间较多的应用,如地图、企业管理系统或多模块设置界面。

综合场景

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

  • 电商应用:
    • 底部选项卡:显示主要功能模块(首页、分类、购物车、我的)。
    • 堆栈导航:从列表页跳转到详情页,或从购物车跳转到结算页面。
    • 抽屉导航:从侧边打开“帮助中心”、“关于我们”等功能。

导航行为

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 可以监听导航事件,例如 focusblur

示例代码:
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;
特点:
  • 适合监听路由参数的变化。
  • 不适合全局路由监听。

总结

方法适用场景
useFocusEffect页面聚焦时触发逻辑,推荐用于页面级的事件处理(如数据刷新)。
useNavigationState监听导航器状态变化,适合需要动态判断当前路由的场景。
navigation.addListener精确监听页面的 focusblur 事件,适用于特定页面状态管理。
onStateChange全局导航状态变化监听,适合统计分析等全局场景。
useRoute获取当前路由对象,适合监听路由参数的变化。

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 中的滑动返回手势。
  • 适用于需要完全自定义导航行为的场景。

总结

  1. 自定义返回行为:

    • 使用 navigation.goBack()navigation.pop() 来自定义返回逻辑。
    • 结合条件判断和用户交互来控制返回行为。
  2. 禁用物理返回按钮:

    • 使用 BackHandler 拦截并自定义物理返回按钮的行为。
  3. 禁用滑动返回手势:

    • 使用 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)。你可以这样配置深度链接:

import * as 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 linking = {
  prefixes: ['myapp://'], // 设置协议
  config: {
    screens: {
      Home: '', // 默认首页
      Details: 'details/:id', // 详情页面,URL 中传递参数 id
    },
  },
};

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

export default App;
解释:
  • prefixes:指定支持的 URL 协议,例如 myapp://,表示只有以 myapp:// 开头的 URL 才会触发应用的导航。
  • config:映射 URL 路径和应用中的屏幕。例如,Details 屏幕的 URL 为 myapp://details/:idid 是路径参数,可以在屏幕组件中访问。

2. 处理 URL 中的参数

在深度链接中,URL 的路径参数(如 details/:id)可以传递到目标屏幕。你可以通过 route.params 获取这些参数。

示例:

假设用户访问 myapp://details/123,我们可以在 DetailsScreen 中获取到 id=123

const DetailsScreen = ({ route }) => {
  const { id } = route.params;

  return (
    <View>
      <Text>Details Screen</Text>
      <Text>Item ID: {id}</Text>
    </View>
  );
};

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

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

iOS 配置

在 iOS 中,你需要在 Info.plist 文件中注册应用支持的 URL 类型:

  1. 打开 ios/[your-project]/Info.plist
  2. 添加以下配置:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string> <!-- 配置协议 -->
    </array>
  </dict>
</array>
Android 配置

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

  1. 打开 android/app/src/main/AndroidManifest.xml
  2. 添加以下内容:
<activity
  android:name=".MainActivity"
  android:label="@string/app_name"
  android:launchMode="singleTask"
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
  android:windowSoftInputMode="adjustResize"
  android:theme="@style/AppTheme">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myapp" /> <!-- 配置协议 -->
  </intent-filter>
</activity>

这样,当用户点击 myapp://details/123 时,Android 和 iOS 都能够启动你的应用,并将其导航到对应的页面。


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. 使用深度链接打开特定页面

如果你想在应用中某个时刻手动触发深度链接,直接导航到某个页面,可以使用 Linking.openURL()

import { Linking } from 'react-native';

const openDeepLink = () => {
  Linking.openURL('myapp://details/123'); // 打开详情页
};

总结

功能实现方式
配置深度链接协议和路径使用 linking 配置对象,定义支持的 URL 协议和页面路径映射。
访问 URL 参数通过 route.params 获取深度链接中传递的参数。
配置 iOS 和 Android 支持的 URL在 iOS 的 Info.plist 和 Android 的 AndroidManifest.xml 中配置 URL 协议。
监听 URL 变化使用 Linking.addEventListeneruseLinking 钩子来监听深度链接事件。
手动触发深度链接使用 Linking.openURL() 来手动打开指定的深度链接。

下文预告

《React Native 性能优化》