1

命令安装

// 安装基础包 ^6.0.6
yarn add @react-navigation/native -S
// 安装路由包 ^6.2.5
yarn add @react-navigation/native-stack -S

//RN版本0.65.1 React版本17.0.2
"react": "17.0.2",
"react-native": "0.65.1",

路由配置

包引用

import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator<RootStackParamList>();
const Navigator = Stack.Navigator;
const Screen = Stack.Screen;

路由列表

// 路由页面配置
<NavigationContainer>
    <Stack.Navigator
        initialRouteName={Views.Home}
        screenOptions={{
            headerShadowVisible: false, // android 导航去阴影
            headerTitleAlign: 'center', // 标题居中
            // 设置导航栏字体样式
            headerTitleStyle: {
                fontSize: 17,
                color: '#333333',
                fontFamily: 'PingFangSC-Semibold',
                fontWeight: '700',
            },
            headerLeft: () => headerLeft(),
        }}
    >
        <Stack.Screen
            name={Views.Home}
            component={Home}
            options={{ title: '每日任务' }}
        />
        <Stack.Screen
            name={Views.NewTask}
            component={NewTask}
            options={{ title: '新手任务' }}
        />
        <Stack.Screen
            name={Views.Redeem}
            component={Redeem}
            options={{ title: '积分兑换' }}
        />
        <Stack.Screen
            name={Views.Rule}
            component={Rule}
            options={{ title: '积分兑换规则' }}
        />
    </Stack.Navigator>
</NavigationContainer>

属性参数详解

Stack.Navigator

导航全局配置,再次配置的参数在所有路由页面的导航上面全部生效,具体属性如下

initialRouteName: //指定路由首页 类比React的跟路由页面
// 用于导航器中屏幕的默认选项
screenOptions: {
    headerShadowVisible: false, // android 导航去阴影 默认true开启状态
    headerTitleAlign: 'center', // 标题居中 默认 'left'
    headerTitle: '标题', //全局标题 在此设置是不生效的 默认展示路由页面的name
    // 设置导航栏字体样式
    headerTitleStyle: {
        fontSize: 17,
        color: '#333333',
        fontFamily: 'PingFangSC-Semibold',
        fontWeight: '700',
    },
    headerTintColor: 'red', // 导航栏字体颜色设置 如果设置了headerTitleStyle则此处设置不生效
    statusBarStyle: 'light' //"inverted" | "auto" | "light" | "dark" | undefined 状态栏配置
    headerLeft: React.ReactNode, //导航左侧区域按钮配置 不配置默认展示左箭头返回图标
    headerRight: React.ReactNode //导航右侧区域配置 默认无
}

以上基础配置基本上能满足绝大多数业务的日常开发了

Stack.Screen

页面导航配置,此处的配置会覆盖全局配置,具体属性参数如下:

const Home = lazy(() => import('./views/home'));
name= 'Home' //指定的路由页面的名称 必填属性
component= Home // 路由React页面挂载 必填属性
initialParams={{ itemId: 42 }} //页面初始化参数
// 路由页面导航配置 此处的配置会覆盖全局的screenOptions
options={{ 
  title: '积分兑换规则', //路由页面标题 
  headerLeft: React.ReactNode, //导航左侧区域按钮配置 不配置默认展示左箭头返回图标
  headerRight: React.ReactNode //导航右侧区域配置 默认无
}}

路由使用

由于新版本的RN基本上都采用Hooks+TypeScript的方式来开发,在使用时好多都需要做类型声明

声明文件

首先添加一个全局声明文件,方便后面的自定义hooks(下面会详细介绍)的调用;

本人的工程开发目录如下:

image-20211218164107497

首先在types下面加一个全局的ts声明文件index.ts 内容如下:

import { RouteProp } from '@react-navigation/native'; // 获取route的props
// 枚举出来所有的路由页面的Name
export enum Views {
    Home = 'Home',
    NewTask = 'NewTask',
    Redeem = 'Redeem',
    Rule = 'Rule',
}
interface NewTaskProps {
    title: string;
    action: string;
    funcName: string;
    params: any;
}
// 定义每个路由页面需要传达到下个页面的参数 在目的页面里面声明要接受的参数
export type RootStackParamList = {
    [Views.Home]: undefined;

    [Views.NewTask]:
        | {
              /** @description 声明往子组件里面的传参 */
              item: NewTaskProps;
              callback: () => void;
          }
        | undefined;
    [Views.Redeem]:
        | {
              /** @description 监听页面返回回调父页面 */ callback: () => void;
          }
        | undefined;
    [Views.Rule]: undefined;
};
// 定义声明每个子路由界面接收的具体数据类型useRoute 后面详解使用
export type RootRouteType = RouteProp<RootStackParamList>;
// This registers which makes navigation fully type-safe.
// https://reactnavigation.org/docs/typescript#specifying-default-types-for-usenavigation-link-ref-etc
// 全局声明useNavigation自定义hooks方法的参数
declare global {
    namespace ReactNavigation {
        interface RootParamList extends RootStackParamList {}
    }
}

自定义hooks

目前react-navigation提供了自定义hooks方法useNavigation、useRoute等,重点讲解一下路由的使用

useNavigation

1、返回监听navigation.goBack()

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

// 左侧返回按钮
const headerLeft = () => {
    // hooks里面获取导航器对象
    const navigation = useNavigation();
    return (
        <TouchableOpacity
            onPress={() => {
                // 如果无法在使用路由退出后 调用native协议关闭当前RN容器
                navigation.canGoBack() ? navigation.goBack() : Alert.alert('路由首页');
            }}
        >
            <Image
                style={{
                    height: 25,
                    width: 25,
                }}
                source={require('./images/back.png')}
            />
        </TouchableOpacity>
    );
};

2、路由跳转navigation.navigate

import React, { FC } from 'react';
import { useNavigation } from '@react-navigation/native';
import { Views } from '@types'; //此处配置了alias 可以直接使用@
const Home: FC = () => {
  // 自定义hooks里面调用导航对象
    const navigation = useNavigation();
  // 普通不带参数跳转
  const jumpNewTask = () => {
    //不带参数的普通跳转 如果没有全局的ReactNavigation声明 按文档调用会报如下错误一的问题
    navigation.navigate(Views.NewTask); 
  }
  // 带参数跳转
  const jumpNewTask = () => {
    //如果不再目的页面做入参的声明会有如下报错(错误二)
    navigation.navigate(Views.NewTask, {
            item: {
                title: '弹窗',
                action: 'CSTShowDialog',
                funcName: 'dialog',
                params: {
                    title: '温馨提示',
                    content: '请上传证件照,否则发帖需要扣费10元',
                    btns: [
                        { color: '#ff552e', text: '确定' },
                        { color: '#000000', text: '取消' },
                    ],
                },
            },
            callback: () => {
                // 新手任务返回首页 拉取积分信息
                getTaskInfo();
            },
        }); 
  }
}

报错一

image-20211218171256398

报错二

image-20211218171833049

3、重写导航navigation.setOptions

import React, { FC, useLayoutEffect, useEffect } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native'
const Redeem: FC = () => {
  const navigation = useNavigation();
    const headerRight = () => {
        return (
            <TouchableOpacity
                onPress={() => {
                    navigation.navigate(Views.Rule);
                }}
            >
                <Text style={styles.headerRight}>兑换规则</Text>
            </TouchableOpacity>
        );
    };
    useLayoutEffect(() => {
        navigation.setOptions({
            headerRight: () => headerRight(),
        });
    }, []);
}

4、路由页面内赋值参数navigation.setParams

import React, { FC, useLayoutEffect } from 'react';
import { View, Text } from 'react-native';
import { useNavigation } from '@react-navigation/native';
const NewTask: FC = () => {
  const navigation = useNavigation();
  useLayoutEffect(() => {
        // 初始化赋值
        navigation.setParams({ testParam: 'test' });
    }, []);
}
export default NewTask;
// 页面内赋值一般要使用?:可选参数的方式声明 否则上个页面的路由跳转会报如下错误
//错误声明
[Views.NewTask]:
        | {
              /** @description 声明往子组件里面的传参 */
              item: NewTaskProps;
              testParam: string;
              callback: () => void;
          }
        | undefined;
// 正确的声明方式
[Views.NewTask]:
        | {
              /** @description 声明往子组件里面的传参 */
              item: NewTaskProps;
              testParam?: string;
              callback: () => void;
          }
        | undefined;

image-20211218173212258

5、其他

其他API暂不做详解

image-20211218173539012

useRoute

路由页面参数接收自定义hooks

1、路由参数接收route.params

import React, { FC, useLayoutEffect } from 'react';
import { View, Text } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
import { RootRouteType } from '@types';
const NewTask: FC = () => {
  const navigation = useNavigation();
  // @react-navigation/native自定义hooks里面获取路由参数对象
  // 错误 未声明直接使用报错如下 图一
  // const route = useRoute();
  // 正确使用方式 先声明后使用RootRouteType如上types里面的声明
  const route = useRoute<RootRouteType>();
  useLayoutEffect(() => {
        // 初始化赋值
        navigation.setParams({ testParam: 'test' });
        // 路由返回时触发调用父页面传入的callback方法,模拟路由回调
            return () => {
            route.params?.callback();
        };
    }, []);
  // 路由参数获取 
  const getParams = () => {
        // 页面获取到的路由参数如下:(图二所示)有父页面路由跳转的传参,有本页面类自己注册的路由页面参数testParam
        const params = route.params;
        console.log(params);
    };
}
export default NewTask;

图一

image-20211218175703512

图二

image-20211218174921946

2、其他

image-20211218181001395

总结

以上是本人业务开发中常用的功能总结,有更深层次的使用,欢迎留言;总结不易,转载请赋原文链接。


兰俊秋雨
5.1k 声望3.5k 粉丝

基于大前端端技术的一些探索反思总结及讨论