跳至主要內容
版本:6.x

在沒有導航屬性的情況下導航

有時候,您需要從無法存取 navigation 屬性的位置觸發導航動作,例如 Redux 中介軟體。對於這種情況,您可以使用 導航容器上的 ref 來傳送導航動作。

請勿在以下情況下使用 ref

  • 您需要在無須傳遞 navigation 屬性的情況下從元件內部導航,請使用 useNavigationref 的行為方式不同,而且許多特定於畫面的輔助方法都不可用。
  • 您需要處理深入連結或通用連結。使用 ref 執行此作業會有許多邊際案例。請參閱 設定連結 以取得更多有關處理深入連結的資訊。
  • 您需要整合到第三方函式庫(例如推送通知、分支等)。請參閱 有關深入連結的第三方整合

於下列情況使用ref

  • 當您使用狀態管理程式庫,例如 Redux,而您需要從中介軟體派送導航動作時。

請注意,通常由使用者動作 (例如按下按鈕) 觸發導航比由 Redux 中介軟體觸發來得更好。在使用者動作時進行導航會讓應用程式感覺反應更靈敏,並提供更好的使用者體驗。因此在使用ref進行導航之前請先考慮這一點。ref是為無法透過現有 API 處理的場景而設計的最後手段,僅應在少見的情況下使用。

用法

您可以透過ref取得根導航物件,並將其傳遞給RootNavigation,我們稍後將用於導航。

// App.js

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

export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}

在下一步中,我們定義了RootNavigation,這個是一個包含派送使用者定義導航動作功能的簡單模組。

// RootNavigation.js

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

export const navigationRef = createNavigationContainerRef();

export function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}

// add other navigation functions that you need and export them

然後,在任何一個 javascript 模組中,匯入RootNavigation並呼叫您從中匯出的函式。您可以在 React 元件之外使用這種方式,而且實際上從 React 元件內部使用它時也能正常運作。

// any js module
import * as RootNavigation from './path/to/RootNavigation.js';

// ...

RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });

除了navigate之外,您還可以新增其他導航動作

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

// ...

export function push(...args) {
if (navigationRef.isReady()) {
navigationRef.dispatch(StackActions.push(...args));
}
}

請注意,階層導航器需要被渲染才能處理此動作。您可能想要查看巢狀導航的文件以取得更多詳情。

在編寫測試時,您可以模擬導航功能,並判斷正確的函式是否以正確的參數被呼叫。

處理初始化

在使用這種模式時,您需要記住幾件事,以避免應用程式中的導航失敗。

  • ref僅在導航容器渲染之後才會被設定,這在處理深度連結時可能會是非同步的
  • 導航器需要被渲染才能處理動作,沒有導航器,ref就無法準備就緒

如果您嘗試在未渲染導航器或導航器完成掛載之前進行導航,它將列印錯誤訊息,並且不會執行任何動作。因此,您需要新增額外的檢查,以決定應用程式掛載前該執行什麼動作。

例如,考慮以下情況,您在應用程式中的某個畫面中有一個畫面,且該畫面在useEffect/componentDidMount時會派送一個 redux 動作。您在中介軟體中偵聽此動作,並嘗試在收到時執行導航。這將會擲回錯誤,因為此時,父導航器尚未完成掛載且尚未準備就緒。父導航器的useEffect/componentDidMount總是在子導航器的useEffect/componentDidMount之後才會被呼叫。

為避免此問題,你可以使用引用上顯示的範例中 isReady() 方法。

// RootNavigation.js

import * as React from 'react';

export const navigationRef = createNavigationContainerRef();

export function navigate(name, params) {
if (navigationRef.isReady()) {
// Perform navigation if the react navigation is ready to handle actions
navigationRef.navigate(name, params);
} else {
// You can decide what to do if react navigation is not ready
// You can ignore this, or add these actions to a queue you can call later
}
}

如果你不確定瀏覽器是否已呈現,你可以呼叫 navigationRef.current.getRootState(),如果你有呈現任何瀏覽器它會傳回有效的狀態物件,否則它會傳回 未定義