导航容器
NavigationContainer
负责管理您的应用程序状态,并将您的顶级导航器链接到应用程序环境。
容器负责平台特定的集成,并提供各种有用的功能
- 与
linking
属性的深度链接集成。 - 为 屏幕跟踪、状态持久化 等通知状态更改。
- 通过使用 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
附加到容器,以访问各种辅助方法,例如,调度导航操作。这应该在您无法访问 navigation
属性的罕见情况下使用,例如 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
回调来在导航容器完成挂载时收到通知。
有关更多详细信息,请参阅 无需导航道具导航 指南。
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);
});
Props
initialState
此属性接受导航器的初始状态。这对于深层链接、状态持久化等情况很有用。
示例
<NavigationContainer initialState={initialState}>
{/* ... */}
</NavigationContainer>
提供自定义初始状态对象将覆盖通过链接配置或从浏览器 URL 获取的初始状态对象。如果您提供初始状态对象,请确保您没有在 web 上传递它,并且没有深层链接要处理。
示例
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
请将导航器的状态对象视为内部对象,并且可能会在次要版本中发生更改。避免使用 导航状态 状态对象中的属性,除非您确实需要它们。如果您无法在不依赖状态对象结构的情况下实现某些功能,请打开一个问题。
每当 导航状态 发生变化时都会调用的函数。它接收新的导航状态作为参数。
您可以使用它来跟踪聚焦屏幕、持久化导航状态等。
示例
<NavigationContainer
onStateChange={(state) => console.log('New state is', state)}
>
{/* ... */}
</NavigationContainer>
onReady
在导航容器及其所有子元素首次完成挂载后调用的函数。您可以使用它来
- 确保
ref
可用。有关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>;
此选项在 Web 上不可用。
linking.subscribe
与 getInitialURL
类似,您可以提供一个自定义的 subscribe
函数来处理任何传入的链接,而不是默认的深度链接处理。subscribe
函数将接收一个监听器作为参数,您可以在每次有新的 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>
此选项在 Web 上不可用。
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
,则需要这样做才能正确支持 Web。
示例
<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 元素。默认值为 null
。
如果您有原生启动画面,请使用 onReady
而不是 fallback
属性。
documentTitle
默认情况下,React Navigation 会自动更新 Web 上的文档标题,以匹配聚焦屏幕的 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 应用程序中,您可能不想将其设置为 true
。这仅在您的导航树像自己的迷你应用程序一样工作,并且不需要导航到它们外部的屏幕时才有用。
如果您需要与第三方组件(如模态或底部工作表)集成,请避免使用它。请考虑使用 自定义导航器。