React Navigation 6.x 路由库使用指南

Viewed 0

最近两个项目都用到了 React Navigation,因此对其使用进行了研究。本文主要介绍 react-navigation 6.x 路由库的基本使用方法。

React Native 项目初始化

首先,打开命令行,切换到要创建 React Native 项目的文件夹,执行以下命令初始化项目:

npx react-native init testRN

这里将项目名设置为 testRN,可根据需要自行修改。

安装 React Native 项目

连接安卓虚拟机或通过 USB 调试的真机,进入创建好的项目根目录,运行 yarn android 安装并启动应用。初次安装完成后,若手机保持连接,后续只需在虚拟机或手机上打开项目应用,然后在 PC 的项目根目录运行 yarn start 启动即可,无需重新安装。若连接断开,可能需要重新安装。启动后,在命令行界面按 r 键可以更新应用。

React Navigation 路由库安装

以下内容基于 Android 端测试,iOS 端未进行验证。一次性安装以下包:

yarn add @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack

对于安卓端,需要进行额外配置。修改 testRN\android\app\src\main\java\com\testrn 目录下的 MainActivity.java 文件,添加以下代码:

import android.os.Bundle;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(null);
}

使用路由库

将 app.js 修改为以下代码:

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 App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

路由跳转与路由传参

以下示例展示如何实现路由跳转和传参:

import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen({navigation}) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

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

const Stack = createNativeStackNavigator();

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

export default App;

设置路由标题

默认情况下,窗口会使用 name 属性作为标题名,但也可以自行设定。例如:

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

这里用 "my home" 代替 "Home" 作为导航标题。当从一级页面跳转到二级页面时,可能需要根据内容动态展示不同标题,此时可以动态配置 title:

<Stack.Screen name="Details" component={DetailsScreen}
   options={({ route }) => ({ title: route.params.title })}
/>

然后在一级页面跳转时传递 title 参数:

<Button
   title="Go to Details"
   onPress={() => navigation.navigate('Details', { title: '二级页面' })}
/>

注意,如果一级页面没有传递 title,最好传递一个空对象或在二级页面设置初始值,以避免报错。此外,还可以使用 navigation.setOptions() 手动更新标题,该方法修改的是 screen 上 options 中的属性:

<Button
   title="Update the title"
   onPress={() => navigation.setOptions({ title: 'Updated!' })}
/>

自定义标题组件

通过设置 headerTitle 回调返回一个函数式组件,可以自定义标题,例如使用图片:

function LogoTitle() {
  return (
    <Image
      style={{ width: 50, height: 50 }}
      source={require('./src/img/details.png')}
    />
  );
}

<Stack.Screen name="Home" component={HomeScreen}
   options={{
     title: 'My home',
     headerTitle: (props) => <LogoTitle {...props} />
   }}
/>

标题按钮

在 screen 的 options 中,可以使用 headerRight 添加按钮:

<Stack.Screen name="Home" component={HomeScreen}
  options={{
    title: 'My home',
    headerTitle: (props) => <LogoTitle {...props} />,
    headerRight: () => (
      <Button
        onPress={() => alert('This is a button!')}
        title="Info"
        color="#fff"
      />
    ),
  }}

此外,headerBackImageSource 可以修改回退按钮的图片:

<Stack.Screen name="Details" component={DetailsScreen}
  options={({ route }) => ({
    title: route.params.title,
    headerBackImageSource: detailsImg,
  })}
/>
0 Answers