react-navigation(6.0.6版本)使用詳解(基於RN0.65*版本)

淺夏晴空發表於2021-12-20

命令安裝

// 安裝基礎包 ^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

總結

以上是本人業務開發中常用的功能總結,有更深層次的使用,歡迎留言;總結不易,轉載請賦原文連結。

相關文章