NavigationContainer
NavigationContainer
負責管理 app 狀態,以及將最高層導航器連結到 app 環境。
這項容器處理特定平台的整合,並提供各種實用功能
- 與
linking
prop 的深度連結整合。 - 針對 畫面追蹤、狀態持續性 等發出狀態變更通知。
- 後使用 React Native 的
BackHandler
API 來處理 Android 上的系統返回按鈕。
用量
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>{/* ... */}</Stack.Navigator>
</NavigationContainer>
);
}
Ref
也可以將 ref
附加到容器,以存取各種輔助方法,例如調度導航動作。當您無法使用 navigation
prop(例如 Redux 中介軟體)時,這應該用於罕見情況。
範例
import {
NavigationContainer,
useNavigationContainerRef,
} from '@react-navigation/native';
function App() {
const navigationRef = useNavigationContainerRef(); // You can also use a regular ref with `React.useRef()`
return (
<View style={{ flex: 1 }}>
<Button onPress={() => navigationRef.navigate('Home')}>Go home</Button>
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
</View>
);
}
如果您使用一般 ref 物件,請記住 ref 在某些情況下(例如啟用連結時)最初可能會為 null
。若要確保 ref 已初始化,您可以使用 onReady
回呼在導航容器完成掛載時收到通知。
請參閱 在沒有 navigation prop 的情況下導航 指南以取得更多詳細資訊。
ref 上的方法
ref 物件包含所有常見的導覽方法,例如 navigate
、goBack
等。請參閱 CommonActions
的文件以取得更多詳細資料。
範例
navigationRef.navigate(name, params);
所有這些方法的反應,就像是在目前焦點畫面上進行呼叫一般。須注意,系統必須要有一個導覽器已完成渲染才能處理這些動作。
除了這些方法之外,ref 物件還包含下列特殊方法
isReady
isReady
方法會傳回 boolean
,用以指示導覽樹是否就緒。當 NavigationContainer
包含至少一個導覽器,且所有導覽器都完成掛載,表示導覽樹已就緒。
這麼一來,你就可以用來判斷是否可以安全地傳送導覽動作而不發生錯誤。請參閱 處理初始化 以取得更多詳細資料。
resetRoot
透過 resetRoot
方法,你可以將導覽樹的狀態重新設定為指定的狀態物件
navigationRef.resetRoot({
index: 0,
routes: [{ name: 'Profile' }],
});
與 reset
方法不同的是,這個動作會施加在根導覽器,而不是目前焦點畫面的導覽器上。
getRootState
getRootState
方法會傳回 導覽狀態 物件,其中包含導覽樹中所有導覽器的導覽狀態
const state = navigationRef.getRootState();
請注意,如果目前沒有導覽器已完成渲染,傳回的 state
物件會是 undefined
。
getCurrentRoute
getCurrentRoute
方法會傳回整個導覽樹中目前焦點畫面的路線物件
const route = navigationRef.getCurrentRoute();
請注意,如果目前沒有導覽器已完成渲染,傳回的 route
物件會是 undefined
。
getCurrentOptions
getCurrentOptions
方法會傳回整個導覽樹中目前焦點畫面的選項
const options = navigationRef.getCurrentOptions();
請注意,如果目前沒有導覽器已完成渲染,傳回的 options
物件會是 undefined
。
addListener
透過 addListener
方法,你可以傾聽下列事件
state
當導航樹中任何導航器的導航狀態發生變更時會觸發事件
const unsubscribe = navigationRef.addListener('state', (e) => {
// You can get the raw navigation state (partial state object of the root navigator)
console.log(e.data.state);
// Or get the full state object with `getRootState()`
console.log(navigationRef.getRootState());
});
這類似於onStateChange
方法。唯一的差別是e.data.state
物件可能包含部分狀態物件,而onStateChange
中的state
參數則永遠會包含完整的狀態物件。
options
當導航樹中目前焦點所在的畫面選項變更時會觸發事件
const unsubscribe = navigationRef.addListener('options', (e) => {
// You can get the new options for the currently focused screen
console.log(e.data.options);
});
小工具
initialState
小工具,接受導航器的初始狀態。這有助於諸如深度連結、狀態持續等情況。
範例
<NavigationContainer initialState={initialState}>
{/* ... */}
</NavigationContainer>
提供自訂初始狀態物件會覆寫透過連結組態或瀏覽器 URL 獲得的初始狀態物件。如果你提供初始狀態物件,請確定沒有在網路傳遞它,且沒有深度連結要處理。
範例
const initialUrl = await Linking.getInitialURL();
if (Platform.OS !== 'web' && initialUrl == null) {
// Only restore state if there's no deep link and we're not on web
}
請參閱狀態持續指南,進一步瞭解如何持續並復原狀態。
onStateChange
將導航器的狀態物件視為內部物件,可能會在次要版本中變更。請避免使用導航狀態狀態物件中的屬性,但index
和routes
除外,除非你真的需要這麼做。若有某些你無法依靠狀態物件結構來達成功能,請開啟問題。
當導航狀態每次變更時呼叫的功能。它會接收到新的導航狀態作為參數。
你可以使用它來追蹤焦點所在畫面、持續導航狀態等。
範例
<NavigationContainer
onStateChange={(state) => console.log('New state is', state)}
>
{/* ... */}
</NavigationContainer>
onReady
導航容器及其所有子項第一次完成安裝後呼叫的功能。你可以使用它來
- 確保
ref
可用。請參閱關於 ref 初始化的說明文件,進一步瞭解相關詳細資訊。 - 隱藏你的原生開機畫面
範例
<NavigationContainer
onReady={() => console.log('Navigation container is ready')}
>
{/* ... */}
</NavigationContainer>
onUnhandledAction
此功能在任何導覽器都沒有處理導覽動作的情況下呼叫。
預設情況下,React Navigation 會在動作未處理時顯示僅限開發人員的錯誤訊息。您可以提供自訂功能來覆寫預設行為。
linking
連結整合的組態用於深層連結、瀏覽器中的 URL 支援等。
範例
import { NavigationContainer } from '@react-navigation/native';
function App() {
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Home: 'feed/:sort',
},
},
};
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
{/* content */}
</NavigationContainer>
);
}
請參閱連結組態指南,瞭解有關如何組態深層連結與 URL 整合的更多詳細資訊。
選項
linking.prefixes
要處理的 URL 前置字元。您可以提供多個前置字元,以支援自訂範例,以及通用連結。
只有符合這些前置字元的 URL 會被處理。解析前會從 URL 移除前置字元。
範例
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort',
},
},
}}
>
{/* content */}
</NavigationContainer>
僅 iOS 和 Android 支援這個功能。
linking.config
組態參數用於調整路徑解析的方式。組態物件應該表示應用程式中導覽器的結構。
例如,如果我們在 Home
畫面中有 Catalog
畫面,並希望它處理「item/:id
」模式
{
screens: {
Home: {
screens: {
Catalog: {
path: 'item/:id',
parse: {
id: Number,
},
},
},
},
}
}
解析選項可以是物件或字串
{
screens: {
Catalog: 'item/:id',
}
}
當指定字串時,等於提供 path
選項。
path
選項是一種與路徑比對的模式。任何從 :
開始的片段會被辨認為具有相同名稱的參數。例如,item/42
會被解析成 { name: 'item', params: { id: '42' } }
。
initialRouteName
選項可確保傳遞該處的路由名稱會存在於導覽器的狀態中,例如對於組態
{
screens: {
Home: {
initialRouteName: 'Feed',
screens: {
Catalog: {
path: 'item/:id',
parse: {
id: Number,
},
},
Feed: 'feed',
},
},
}
}
以及 URL:/item/42
,狀態看起來會像這樣
{
routes: [
{
name: 'Home',
state: {
index: 1,
routes: [
{
name: 'Feed'
},
{
name: 'Catalog',
params: { id: 42 },
},
],
},
},
],
}
parse
選項控制參數的解析方式。在這裡,您可以提供要解析為關鍵字的參數名稱,以及一個會擷取參數的字串值並傳回已解析值的函式。
{
screens: {
Catalog: {
path: 'item/:id',
parse: {
id: id => parseInt(id, 10),
},
},
}
}
如果沒有提供用於解析參數的自訂函式,該參數會被解析為字串。
linking.enabled
選用的布林值,用於啟用或停用連結整合。如果指定 linking
屬性,則預設為 true
。
linking.getInitialURL
預設情況下,連結整合至 React Native 的 Linking
API 中,並使用 Linking.getInitialURL()
提供深入連結的內建支援。不過,您可能也想要處理來自其他來源的連結,例如 Branch 或使用 Firebase 等發出的推播通知。
您可以提供自訂的 getInitialURL
函式,您可以在其中傳回我們該用作初始 URL 的連結。如果沒有要處理的 URL,getInitialURL
函式應傳回 string
;否則傳回 undefined
。
例如,您可以執行類似以下動作來處理深入連結和 Firebase 通知
import messaging from '@react-native-firebase/messaging';
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort',
},
},
async getInitialURL() {
// Check if app was opened from a deep link
const url = await Linking.getInitialURL();
if (url != null) {
return url;
}
// Check if there is an initial firebase notification
const message = await messaging().getInitialNotification();
// Get the `url` property from the notification which corresponds to a screen
// This property needs to be set on the notification payload when sending it
return message?.data?.url;
},
}}
>
{/* content */}
</NavigationContainer>;
這個選項在網頁上無法使用。
linking.subscribe
類似於 getInitialURL
,您可以提供自訂的 subscribe
函式來處理所有接收到的連結,而不是預設的深入連結處理。subscribe
函式會接收一個偵聽器作為參數,如果有一個新的要處理的 URL,您可以用 URL 字串來呼叫它。它應傳回一個清除函式,讓您可以取消訂閱您設定的任何事件偵聽器。
例如,您可以執行類似以下動作來處理深入連結和 Firebase 通知
import messaging from '@react-native-firebase/messaging';
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort',
},
},
subscribe(listener) {
const onReceiveURL = ({ url }: { url: string }) => listener(url);
// Listen to incoming links from deep linking
const subscription = Linking.addEventListener('url', onReceiveURL);
// Listen to firebase push notifications
const unsubscribeNotification = messaging().onNotificationOpenedApp(
(message) => {
const url = message.data?.url;
if (url) {
// Any custom logic to check whether the URL needs to be handled
//...
// Call the listener to let React Navigation handle the URL
listener(url);
}
}
);
return () => {
// Clean up the event listeners
subscription.remove();
unsubscribeNotification();
};
},
}}
>
{/* content */}
</NavigationContainer>
這個選項在網頁上無法使用。
linking.getStateFromPath
您可以選擇提供自己的實作,以覆寫 React Navigation 將連結剖析為狀態物件的方式。
範例
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort',
},
},
getStateFromPath(path, config) {
// Return a state object here
// You can also reuse the default logic by importing `getStateFromPath` from `@react-navigation/native`
},
}}
>
{/* content */}
</NavigationContainer>
linking.getPathFromState
您可以選擇提供自己的實作,以覆寫 React Navigation 將狀態物件序列化為連結的方式。如果您指定了 getStateFromPath
,則網頁支援需要這樣做。
範例
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort',
},
},
getPathFromState(state, config) {
// Return a path string here
// You can also reuse the default logic by importing `getPathFromState` from `@react-navigation/native`
},
}}
>
{/* content */}
</NavigationContainer>
fallback
在我們解析深入連結時,使用為備用內容的 React Element。預設為 null
。
如果您有原生的載入畫面,請使用 onReady
,而不是 fallback
屬性。
documentTitle
預設情況下,React Navigation 會在網頁上自動更新文件標題,以符合焦點畫面的 title
選項。您可以使用這個屬性停用或自訂它。它接受具有下列選項的設定物件
documentTitle.enabled
文件標題處理是否應啟用。預設為 true
。
documentTitle.formatter
如果您想要自訂標題文字,可以使用自訂格式化器。預設為
(options, route) => options?.title ?? route?.name;
範例
import { NavigationContainer } from '@react-navigation/native';
function App() {
return (
<NavigationContainer
documentTitle={{
formatter: (options, route) =>
`${options?.title ?? route?.name} - My Cool App`,
}}
>
{/* content */}
</NavigationContainer>
);
}
theme
自訂佈景主題供導覽元件(例如標頭、分頁欄等)使用。如需詳情以及使用說明,請參閱佈景主題指南。
independent
這是進階使用範例。除非您 100% 確定需要,否則請勿使用它。
這個導覽容器是否應該與父層容器獨立。如果這設定為 true
,這個容器不能巢狀於另一個容器之中。將它設定為 true
會斷開任何子層導覽器與父層容器的連結,並禁止它們之間的導覽。
在典型的 React Native App 中,您可能不想將它設定為 true
。這僅適用於導覽樹狀結構以其 mini-app 自行運作,而無需導覽至其外部的畫面。
如果您需要與第三方元件(例如模組或底端表單)整合,請避免使用這個。請考慮改用自訂導覽器。