NavigationContainer
NavigationContainer 负责管理你的应用程序的导航状态,并将你的顶层导航器链接到应用程序环境。
容器负责特定于平台的集成,并提供各种有用的功能
- 通过
linking属性进行深度链接集成。 - 通知状态更改以进行 屏幕追踪、状态持久化 等。
- 通过使用 React Native 的
BackHandlerAPI 处理 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)集成,请避免使用此方法。考虑使用 自定义导航器。