NavigationContainer
NavigationContainer
负责管理你的应用程序的导航状态,并将你的顶层导航器链接到应用程序环境。
容器负责特定于平台的集成,并提供各种有用的功能
- 通过
linking
属性进行深度链接集成。 - 通知状态更改以进行 屏幕追踪、状态持久化 等。
- 通过使用 React Native 的
BackHandler
API 处理 Android 上的系统返回按钮。
用法
- 静态
- 动态
当使用静态 API 时,由 createStaticNavigation
返回的组件等同于 NavigationContainer
组件。
import { createStaticNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator({
screens: {
/* ... */
},
});
const Navigation = createStaticNavigation(Stack);
export default function App() {
return <Navigation />;
}
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
对象 时,例如 Redux 中间件。
示例
- 静态
- 动态
import {
createStaticNavigation,
useNavigationContainerRef,
} from '@react-navigation/native';
export default 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>
<Navigation ref={navigationRef} />
</View>
);
}
import {
NavigationContainer,
useNavigationContainerRef,
} from '@react-navigation/native';
export default 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}>
<Stack.Navigator initialRouteName="Empty">
<Stack.Screen name="Empty" component={() => <View></View>} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
</View>
);
}
如果你正在使用常规的 ref 对象,请记住在某些情况下(例如启用链接时),ref 最初可能是 null
。为了确保 ref 已初始化,你可以使用 onReady
回调以在导航容器完成挂载时收到通知。
查看如何使用 TypeScript 设置 ref
此处。
有关更多详细信息,请参阅 在没有导航 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);
});
Props
initialState
接受导航器初始状态的 Prop。这对于深度链接、状态持久化等情况很有用。
示例
- 静态
- 动态
<Navigation
initialState={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
将导航器的状态对象视为内部对象,并且在小版本更新中可能会发生更改。除非你真的需要,否则避免使用 导航状态 状态对象中的属性,除了 index
和 routes
。如果有一些功能你无法在不依赖状态对象结构的情况下实现,请提出 issue。
每次 导航状态 更改时都会调用的函数。它接收新的导航状态作为参数。
你可以使用它来跟踪聚焦的屏幕、持久化导航状态等。
示例
- 静态
- 动态
<Navigation
onStateChange={(state) => console.log('New state is', state)}
/>
<NavigationContainer
onStateChange={(state) => console.log('New state is', state)}
>
{/* ... */}
</NavigationContainer>
onReady
在导航容器及其所有子项首次完成挂载后调用的函数。你可以将其用于
- 确保
ref
可用。有关更多详细信息,请参阅 有关 ref 初始化的文档。 - 隐藏你的原生启动画面
示例
- 静态
- 动态
<Navigation
onReady={() => console.log('Navigation container is ready')}
/>
<NavigationContainer
onReady={() => console.log('Navigation container is ready')}
>
{/* ... */}
</NavigationContainer>
如果容器内没有渲染导航器,则此回调不会触发。
可以使用 ref 上的 isReady
方法获取当前状态。
onUnhandledAction
当导航操作未被任何导航器处理时调用的函数。
默认情况下,当操作未被处理时,React Navigation 将显示仅在开发环境中显示错误消息。你可以通过提供自定义函数来覆盖默认行为。
示例
- 静态
- 动态
<Navigation
onUnhandledAction={(action) => console.error('Unhandled action', action)}
/>
<NavigationContainer
onUnhandledAction={(action) => console.error('Unhandled action', action)}
>
{/* ... */}
</NavigationContainer>
linking
用于深度链接、浏览器中的 URL 支持等的链接集成配置。
示例
- 静态
- 动态
import { createStaticNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const RootStack = createNativeStackNavigator({
screens: {
Home: {
screen: Home,
linking: {
path: 'feed/:sort',
},
},
},
});
const Navigation = createStaticNavigation(RootStack);
function App() {
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
};
return (
<Navigation
linking={linking}
fallback={<Text>Loading...</Text>}
/>
);
}
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 前缀。你可以提供多个前缀以支持自定义 scheme 以及 通用链接。
只有与这些前缀匹配的 URL 才会被处理。前缀将在解析之前从 URL 中剥离。
示例
- 静态
- 动态
<Navigation
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
}}
fallback={<Text>Loading...</Text>}
/>
<NavigationContainer
linking={{
// highlight-next-lineP
prefixes: ['https://mychat.com', 'mychat://'],
config: {
// ...
},
}}
>
{/* content */}
</NavigationContainer>
仅在 iOS 和 Android 上支持。
linking.config
用于微调如何解析路径的配置。
当使用动态 API 时,config 对象应表示应用程序中导航器的结构。
有关如何配置深度链接和 URL 集成的更多详细信息,请参阅 配置链接指南。
linking.enabled
可选的布尔值,用于启用或禁用链接集成。如果指定了 linking
属性,则默认为 true
。
当使用静态 API 时,可以传递 'auto'
以基于导航器的结构自动生成 config。有关更多详细信息,请参阅 配置链接指南。
linking.getInitialURL
默认情况下,链接与 React Native 的 Linking
API 集成,并使用 Linking.getInitialURL()
来提供对深度链接的内置支持。但是,你可能还想处理来自其他来源的链接,例如 Branch,或使用 Firebase 等的推送通知。
你可以提供自定义的 getInitialURL
函数,你可以在其中返回我们应该用作初始 URL 的链接。如果存在要处理的 URL,则 getInitialURL
函数应返回一个 string
,否则返回 undefined
。
例如,你可以执行以下操作来同时处理深度链接和 Firebase 通知
- 静态
- 动态
import messaging from '@react-native-firebase/messaging';
<Navigation
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
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;
},
}}
/>;
import messaging from '@react-native-firebase/messaging';
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
// ...
},
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 要处理时,你都可以使用 URL 字符串调用它。它应该返回一个清理函数,你可以在其中取消订阅你已设置的任何事件监听器。
例如,你可以执行以下操作来同时处理深度链接和 Firebase 通知
- 静态
- 动态
import messaging from '@react-native-firebase/messaging';
<Navigation
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
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();
};
},
}}
/>
import messaging from '@react-native-firebase/messaging';
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
// ...
},
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 将链接解析为状态对象的方式。
示例
- 静态
- 动态
<Navigation
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
getStateFromPath(path, config) {
// Return a state object here
// You can also reuse the default logic by importing `getStateFromPath` from `@react-navigation/native`
},
}}
/>
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
// ...
},
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 支持,这是必要的。
示例
- 静态
- 动态
<Navigation
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
getPathFromState(state, config) {
// Return a path string here
// You can also reuse the default logic by importing `getPathFromState` from `@react-navigation/native`
},
}}
/>
<NavigationContainer
linking={{
prefixes: ['https://mychat.com', 'mychat://'],
config: {
// ...
},
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
。
- 静态
- 动态
<Navigation
fallback={<Text>Loading...</Text>}
/>
<NavigationContainer
fallback={<Text>Loading...</Text>}
>
{/* content */}
</NavigationContainer>
如果你有原生启动画面,请使用 onReady
而不是 fallback
属性。
documentTitle
默认情况下,React Navigation 会自动更新 Web 上的文档标题以匹配聚焦屏幕的 title
选项。你可以禁用它或使用此属性自定义它。它接受具有以下选项的配置对象
documentTitle.enabled
是否应启用文档标题处理。默认为 true
。
documentTitle.formatter
如果你想自定义标题文本,可以使用自定义格式化程序。默认为
(options, route) => options?.title ?? route?.name;
示例
- 静态
- 动态
<Navigation
documentTitle={{
formatter: (options, route) =>
`${options?.title ?? route?.name} - My Cool App`,
}}
/>
<NavigationContainer
documentTitle={{
formatter: (options, route) =>
`${options?.title ?? route?.name} - My Cool App`,
}}
>
{/* content */}
</NavigationContainer>
theme
用于导航组件(如标题、标签栏等)的自定义主题。有关更多详细信息和使用指南,请参阅 主题指南。
direction
应用程序中配置的文本方向。当 I18nManager.getConstants().isRTL
返回 true
时,默认为 'rtl'
,否则为 'ltr'
。
支持的值
'ltr'
:从左到右的文本方向,适用于英语、法语等语言。'rtl'
:从右到左的文本方向,适用于阿拉伯语、希伯来语等语言。
示例
- 静态
- 动态
<Navigation
direction="rtl"
/>
<NavigationContainer
direction="rtl"
>
{/* content */}
</NavigationContainer>
这在各种导航器中用于根据文本方向调整内容,例如,在 RTL 语言中,抽屉导航器 中的抽屉位于右侧。
此属性告知 React Navigation 应用程序中的文本方向,它本身不会更改文本方向。如果你打算支持 RTL 语言,则务必将此属性设置为应用程序中配置的正确值。如果它与实际文本方向不匹配,则布局可能不正确。
在 Web 上,可能还需要在应用程序的根元素上设置 dir
属性,以确保文本方向正确
<html dir="rtl">
<!-- App content -->
</html>
direction
将通过 useLocale
hook 在你自己的组件中使用
import { useLocale } from '@react-navigation/native';
function MyComponent() {
const { direction } = useLocale();
// Use the direction
}
navigationInChildEnabled
此属性出于向后兼容性原因而存在。不建议在新项目中使用它。它将在未来的版本中删除。
在 React Navigation 的先前版本中,可以在不指定父屏幕名称的情况下导航到嵌套导航器中的屏幕,即 navigation.navigate(ScreenName)
而不是 navigation.navigate(ParentScreenName, { screen: ScreenName })
。
但是,它有一些问题
- 它仅在导航器已挂载时才有效 - 使导航与其他逻辑耦合。
- 它不适用于 TypeScript 类型。
navigationInChildEnabled
属性允许你选择加入此行为,以便更轻松地迁移旧代码。默认情况下禁用它。
对于新代码,请参阅 导航到嵌套导航器中的屏幕。
独立的导航容器
这是一个高级用例。除非你 100% 确定你需要它,否则不要使用它。
在大多数应用程序中,将只有一个 NavigationContainer
。嵌套多个 NavigationContainer
将抛出错误。但是,在极少数情况下,拥有多个独立的导航树可能很有用,例如,在一个较大的应用程序中包含一个小型应用程序。
你可以使用 NavigationIndependentTree
组件包装嵌套的 NavigationContainer
,使其独立于父导航树
- 静态
- 动态
import {
createStaticNavigation,
NavigationIndependentTree,
} from '@react-navigation/native';
/* content */
const Navigation = createStaticNavigation(RootStack);
function NestedApp() {
return (
<NavigationIndependentTree>
<Navigation />
</NavigationIndependentTree>
);
}
import {
NavigationContainer,
NavigationIndependentTree,
} from '@react-navigation/native';
function NestedApp() {
return (
<NavigationIndependentTree>
<NavigationContainer>{/* content */}</NavigationContainer>
</NavigationIndependentTree>
);
}
这样做会断开任何子导航器与父容器的连接,并且不允许它们之间进行导航。
如果你需要与第三方组件(如模态框或底部 sheet)集成,请避免使用此方法。考虑使用 自定义导航器。