跳到主要内容
版本:7.x

从 6.x 版本升级

React Navigation 7 专注于简化 API,以避免可能导致错误的模式。这意味着弃用一些为了向后兼容性而保留的遗留行为。

本指南列出了从 React Navigation 6 升级到 React Navigation 7 时需要注意的所有重大更改和新功能。

最低要求

  • react-native >= 0.72.0
  • expo >= 52 (如果您使用 Expo Go)
  • typescript >= 5.0.0(如果您使用 TypeScript)

重大更改

navigate 操作的更改

navigate 方法不再导航到嵌套子导航器中的屏幕

由于向后兼容性原因,React Navigation 5 和 6 支持使用 navigation.navigate(ScreenName) 语法导航到嵌套子导航器中的屏幕。但这存在问题

  • 它仅在导航器已挂载时才有效 - 使导航与其他逻辑耦合。
  • 它不适用于 TypeScript 类型。

由于这些问题,我们有一个特殊的 API 来导航到嵌套屏幕 (navigation.navigate(ParentScreenName, { screen: ScreenName }))。

从这个版本开始,这不再是默认行为。如果您在应用中依赖此行为,您可以将 navigationInChildEnabled 属性传递给 NavigationContainer 以保留该行为,直到您能够迁移为止

<NavigationContainer navigationInChildEnabled>{/* ... */}</NavigationContainer>

navigationInChildEnabled 属性将在下一个主要版本中删除。

有关更新后的用法,请参阅 navigate

navigate 方法不再返回,请改用 popTo

以前,如果屏幕已存在于堆栈中,则 navigate 方法会返回。我们看到很多人对此行为感到困惑。

为了避免这种混淆,我们从 navigate 中移除了返回行为,并添加了一个 新方法 popTo,以显式返回堆栈中的特定屏幕

navigation.navigate('PreviousScreen', { foo: 42 });
navigation.popTo('PreviousScreen', { foo: 42 });

这些方法现在的行为如下

  • 如果屏幕已聚焦,则 navigate(screenName) 将停留在当前屏幕上,否则将新屏幕推入堆栈。
  • 如果屏幕存在于堆栈中,则 popTo(screenName) 将返回到该屏幕,否则弹出当前屏幕并将此屏幕添加到堆栈。

有关更多详细信息,请参阅 popTo

为了实现与之前的 navigate 类似的行为,您可以使用 getId 属性,在这种情况下,它将转到具有匹配 ID 的屏幕,并相应地推送或弹出屏幕。

为了帮助迁移,我们添加了一个名为 navigateDeprecated 的新方法,它的行为将类似于旧的 navigate 方法。您可以将当前的 navigate 调用替换为 navigateDeprecated,以逐步迁移到新行为

navigation.navigate('SomeScreen');
navigation.navigateDeprecated('SomeScreen');

navigateDeprecated 方法将在下一个主要版本中删除。

navigate 方法不再接受 key 选项

以前,您可以指定路由 key 以导航到,例如

navigation.navigate({ key: 'someuniquekey' })`

这存在问题,因为

  • key 是库内部的实现细节,由库内部创建 - 这使得使用起来很奇怪。
  • 其他操作都不支持这种用法。
  • 指定 key 不是类型安全的,很容易导致错误。

在 React Navigation 5 中,我们添加了 getId 属性,它可以用于类似的用例 - 并且让用户完全控制,因为他们提供 ID,而不是由库自动生成。

因此,key 选项现在已从 navigate 操作中删除。

有关更新后的用法,请参阅 navigate

NavigationContainer 的更改

NavigationContainer 上的 onReady 回调现在仅在渲染导航器时触发

以前,onReady 属性和 navigationRef.isReady() 的工作方式略有不同

  • NavigationContainer 完成挂载并且深度链接已解析时,onReady 回调会触发。
  • navigationRef.isReady() 方法还会检查是否渲染了任何导航器 - 如果用户在 NavigationContainer 内有条件地渲染其导航器,则可能并非如此。

了解这一点很重要,因为如果没有渲染导航器,我们将无法调度任何导航操作,因为没有导航器来处理它们。但是 onReadynavigationRef.isReady() 之间的不一致很容易导致问题和混淆。

此更改使 onReady 的工作方式类似于 navigationRef.isReady()onReady 回调现在仅在渲染导航器时触发 - 反映 navigationRef.isReady() 的值。

此更改对于大多数用户来说不是破坏性的,因此您可能不需要执行任何操作。

有关用法,请参阅 onReady

NavigationContainer 上的 independent 属性已被删除,取而代之的是 NavigationIndependentTree 组件

NavigationContainer 上的 independent 属性是为了支持在与应用其余部分分离的树中渲染导航器而添加的。这对于微应用等用例很有用。

但是,这种方法存在问题

  • 在构建微应用时,添加此属性的责任在于微应用开发者,这并不理想,因为忘记它可能会导致问题。
  • 许多初学者错误地添加了此属性,并且对导航不起作用感到困惑。

因此,我们移除了此属性,取而代之的是 NavigationIndependentTree 组件,您可以使用它来包装导航容器

<NavigationContainer independent>
{/* ... */}
</NavigationContainer>
<NavigationIndependentTree>
<NavigationContainer>
{/* ... */}
</NavigationContainer>
</NavigationIndependentTree>

这样,责任不再在于微应用开发者,而在于父应用。初学者也很难意外添加它。

有关用法,请参阅 独立的导航容器

theme 属性现在接受 fonts 属性

以前,NavigationContainer 上的 theme 属性接受 colors 属性来自定义 React Navigation 中各种 UI 元素使用的颜色。我们现在添加了 fonts 属性来自定义字体。如果您在 theme 属性中传递自定义主题,则需要更新它以包含 fonts 属性。

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

const theme = {
colors: {
// ...
},
fonts: DefaultTheme.fonts,
};

如果您想自定义字体,请参阅 主题指南 以获取更多详细信息。

链接的更改

路径位置中参数的编码现在更加宽松

以前,无论参数的位置(例如查询位置,如 ?user=jane 或路径位置,如 /users/jane),在为屏幕生成链接(例如 Web 上的 URL)时,参数始终使用 encodeURIComponent 进行 URL 编码。这使得在参数中使用特殊字符变得困难。

现在,只有查询位置中的参数进行 URL 编码。对于路径位置中的参数,我们仅对路径位置中不允许的字符进行编码。

通过此更改,在路径中使用特殊字符(例如 @)变得更容易。例如,要拥有类似 profile/@username 的 URL,您可以在链接配置中使用以下内容

const config = {
prefixes: ['https://mysite.com'],
config: {
screens: {
Profile: {
path: 'profile/:username',
parse: {
username: (username) => username.replace(/^@/, ''),
},
stringify: {
username: (username) => `@${username}`,
},
},
},
},
};

有关链接配置的用法,请参阅 配置链接

以前,Link 组件和 useLinkProps hook 被设计为通过 to 属性与路径字符串一起使用。但这有一些问题

  • 路径字符串不是类型安全的,在重构后很容易导致拼写错误和错误
  • 即使屏幕名称是首选方法,API 也使得通过屏幕名称进行导航更加不方便

现在,它们不再接受接受路径字符串的 to 属性,而是接受 screenparams 属性,以及可选的 href 属性,以代替生成的路径

<Link to="/details?foo=42">Go to Details</Link>
<Link screen="Details" params={{ foo: 42 }}>Go to Details</Link>

const props = useLinkProps({ to: '/details?foo=42' });
const props = useLinkProps({ screen: 'Details', params: { foo: 42 } });

通过此更改,如果您已配置全局类型,则在使用 Link 组件时,您现在将具有完全的类型安全性。

有关用法,请参阅 LinkuseLinkProps

useLinkBuilder hook 现在返回一个对象而不是一个函数

以前,useLinkBuilder hook 返回一个函数来为屏幕构建 href - 这主要用于构建自定义导航器。现在,它返回一个带有 buildHrefbuildAction 方法的对象

const { buildHref, buildAction } = useLinkBuilder();

const href = buildHref('Details', { foo: 42 }); // '/details?foo=42'
const action = buildAction('/details?foo=42'); // { type: 'NAVIGATE', payload: { name: 'Details', params: { foo: 42 } } }

buildHref 方法的作用与之前返回的函数相同。新的 buildAction 方法可用于从 href 字符串构建导航操作。

请注意,此 hook 旨在主要由自定义导航器使用,而不是由最终用户使用。对于最终用户,Link 组件和 useLinkProps 是推荐的导航方式。

有关用法,请参阅 useLinkBuilder

导航器的更改

在模态框之上推送的屏幕现在在堆栈和原生堆栈导航器中显示为模态框

以前,在模态框之上推送的屏幕在堆栈和原生堆栈导航器中显示为常规屏幕。这经常在堆栈导航器上导致动画卡顿,并在原生堆栈导航器上出现在模态框后面。如果用户从深度链接来到屏幕,这尤其令人困惑。

现在,在模态框之上推送的屏幕会自动显示为模态框,以避免这些问题。可以通过显式将 presentation 选项设置为 card 来禁用此行为

<Stack.Screen
name="MyModal"
component={MyModalScreen}
options={{
presentation: 'card',
}}
/>

有关用法,请参阅 堆栈导航器原生堆栈导航器 文档。

headerBackTitleVisible 已被删除,取而代之的是堆栈和原生堆栈导航器中的 headerBackButtonDisplayMode

以前,可以使用 headerBackTitleVisible 来控制是否在标题中显示后退按钮标题。它现在已被删除,取而代之的是提供更多灵活性的 headerBackButtonDisplayMode

可以通过分别将 headerBackButtonDisplayMode 设置为 defaultminimal 来实现以前的行为,以显示和隐藏后退按钮标题

<Stack.Screen
name="Details"
component={DetailsScreen}
options={{
headerBackTitleVisible: false,
headerBackButtonDisplayMode: 'minimal',
}}
/>

animationEnabled 选项已删除,取而代之的是堆栈导航器中的 animation 选项

以前,animationEnabled: false 用于禁用堆栈导航器中屏幕过渡的动画。

现在有一个新的 animation 属性来配置动画,类似于原生堆栈。因此,您现在可以使用 animation: 'none' 来禁用动画

<Stack.Screen
name="Details"
component={DetailsScreen}
options={{
animationEnabled: false,
animation: 'none',
}}
/>

有关用法,请参阅 堆栈导航器动画

customAnimationOnGesture 在原生堆栈导航器中重命名为 animationMatchesGesture

原生堆栈导航器中的 customAnimationOnGesture 选项已重命名为 animationMatchesGesture,以更好地反映其用途。如果您在项目中使用 customAnimationOnGesture,则可以将其重命名为 animationMatchesGesture

<Stack.Navigator options={{ customAnimationOnGesture: true }}>
<Stack.Navigator options={{ animationMatchesGesture: true }}>

有关用法,请参阅 原生堆栈导航器

statusBarColor 在原生堆栈导航器中重命名为 statusBarBackgroundColor

原生堆栈导航器中的 statusBarColor 选项已重命名为 statusBarBackgroundColor,以更好地反映其用途。如果您在项目中使用 statusBarColor,则可以将其重命名为 statusBarBackgroundColor

<Stack.Navigator options={{ statusBarColor: 'tomato' }}>
<Stack.Navigator options={{ statusBarBackgroundColor: 'tomato' }}>

有关用法,请参阅 原生堆栈导航器

原生堆栈现在需要 react-native-screens 4

@react-navigation/native-stack 现在需要 react-native-screens 4,并且在使用早期版本时会中断。如果您在项目中使用原生堆栈导航器,请确保将 react-native-screens 升级到版本 4。

有关用法,请参阅 原生堆栈导航器

Material Top Tab Navigator 不再需要安装 react-native-tab-view

以前,@react-navigation/material-top-tabs 需要安装 react-native-tab-view 作为项目中的依赖项。我们现在已将此软件包移动到 React Navigation monorepo,并且能够协调发布,因此不再需要单独安装它。

如果您使用 @react-navigation/material-top-tabs 并且不在项目的其他任何地方使用 react-native-tab-view,则可以在升级后将其从依赖项中删除。

如果您出于某种原因需要强制使用特定版本的 react-native-tab-view,我们建议使用 Yarn resolutionsnpm overrides 来实现。

有关用法,请参阅 Material Top Tab Navigator

unmountOnBlur 选项已删除,取而代之的是底部标签导航器和抽屉导航器中的 popToTopOnBlur

在许多情况下,所需的行为是在标签或抽屉导航器中嵌套的堆栈取消聚焦后返回到堆栈的第一个屏幕。以前,unmountOnBlur 选项用于实现此行为。但是,它有一些问题

  • 它销毁了堆栈中屏幕的本地状态。
  • 在标签导航上重新挂载嵌套导航器很慢。

popToTopOnBlur 选项提供了一种替代方法 - 它弹出嵌套堆栈上的屏幕以返回到堆栈中的第一个屏幕,并且没有上述问题。

有关用法,请参阅 底部标签导航器抽屉导航器 文档。

仍然可以通过在屏幕中使用 useIsFocused hook 来实现旧的 unmountOnBlur 行为

const isFocused = useIsFocused();

if (!isFocused) {
return null;
}

这也可以与新的 布局属性 结合使用,以在屏幕配置级别指定它。

tabBarTestID 选项在底部标签导航器和 Material Top Tab Navigator 中重命名为 tabBarButtonTestID

@react-navigation/bottom-tabs@react-navigation/material-top-tabs 中的 tabBarTestID 选项已重命名为 tabBarButtonTestID,以更好地反映其用途。如果您在项目中使用 tabBarTestID,则可以将其重命名为 tabBarButtonTestID

<Tab.Navigator tabBarOptions={{ tabBarTestID: 'test-id' }}>
<Tab.Navigator tabBarOptions={{ tabBarButtonTestID: 'test-id' }}>

有关用法,请参阅 底部标签导航器Material Top Tab Navigator 文档。

sceneContainerStyle 属性和选项已从底部标签导航器、Material Top Tab Navigator 和抽屉导航器中删除,取而代之的是 sceneStyle

以前,底部标签导航器和 Material Top Tab Navigator 接受 sceneContainerStyle 属性来设置场景容器的样式。这是不灵活的,因为它不允许为不同的屏幕设置不同的样式。现在,这些导航器添加了 sceneStyle 选项来设置各个屏幕的样式。

同样,抽屉导航器中的 sceneContainerStyle 选项已重命名为 sceneStyle,以保持一致性。

如果您使用 sceneContainerStyle 属性,则可以在 screenOptions 中传递 sceneStyle 以保持相同的行为

<Tab.Navigator sceneContainerStyle={{ backgroundColor: 'white' }}>
<Tab.Navigator screenOptions={{ sceneStyle: { backgroundColor: 'white' } }}>

抽屉导航器现在需要在原生平台上使用 Reanimated 2 或 3

以前,@react-navigation/drawer 使用 useLegacyImplementation 选项支持 Reanimated 1 和 Reanimated 2 API。现在不再支持此选项,并且 useLegacyImplementation 选项已删除。

如果您在项目中使用 Reanimated 1,则需要升级到 Reanimated 2 或 3 才能使用 @react-navigation/drawer

如果您在 Web 上使用抽屉导航器,它现在将使用 CSS 过渡而不是 Reanimated,以减小捆绑包大小。

有关用法,请参阅 抽屉导航器

元素的更改

labelVisible 已被删除,取而代之的是 headerLeftHeaderBackButton 元素中的 displayMode

以前,可以使用 labelVisible 来控制是否在标题中显示后退按钮标题。它现在已被删除,取而代之的是提供更多灵活性的 displayMode

新的可能值是

  • default:根据可用空间显示以下内容之一:上一个屏幕的标题、通用标题(例如“返回”)或无标题(仅图标)。
  • generic:根据可用空间显示以下内容之一:通用标题(例如“返回”)或无标题(仅图标)。仅限 iOS >= 14,在旧版本 iOS 上回退到“default”。
  • minimal:始终仅显示图标,不带标题。

可以通过分别将 displayMode 设置为 defaultgeneric 来显示和将 minimal 设置为隐藏后退按钮标题来实现以前的行为

<HeaderBackButton
labelVisible={false}
displayMode="minimal"
/>

弃用和删除

Material Bottom Tab Navigator 现在位于 react-native-paper 软件包中

@react-navigation/material-bottom-tabs 软件包为 react-native-paperBottomNavigation 组件提供了 React Navigation 集成。为了更容易地使其与 react-native-paper 中的更改保持同步,我们现在已将其移动到 react-native-paper 软件包。

如果您在项目中使用 @react-navigation/material-bottom-tabs,则可以将其从依赖项中删除,并将导入更改为 react-native-paper/react-navigation

import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
import { createMaterialBottomTabNavigator } from 'react-native-paper/react-navigation';

有关用法,请参阅 Material Bottom Tab Navigator

或者,您可以将 BottomNavigation.Bar 组件用作带有 @react-navigation/bottom-tabs 的自定义标签栏。

对于与 Material Bottom Tab Navigator 或 BottomNavigation.Bar 相关的任何问题,请在 react-native-paper 存储库 中打开它们,而不是在 React Navigation 存储库中打开。

flipper devtools 插件现已删除

以前,我们为 React Navigation 添加了一个 Flipper 插件,以使调试导航更容易。但是,它为我们增加了大量的维护开销。Flipper 团队最近没有专注于 React Native,因此使用 Flipper 和 React Native 的总体体验一直很差。

目前,Flipper 团队一直专注于原生开发者体验,因此我们正在回到绘图板。我们在团队内创建了一个新的支柱,专注于开发者体验。我们目前正在调查 Hermes 团队改进的 Chrome 调试器协议支持,以及将调试体验从 Flipper 迁移到 Chrome DevTools,以便我们可以提供符合我们标准的调试体验。

react-native-community/discussions-and-proposals#546 (comment)

由于 React Native 团队正在从 Flipper 迁移,因此我们花费额外的资源来继续支持它没有多大意义。因此,我们已从 @react-navigation/devtools 中删除了 Flipper 插件。

或者,您可以使用以下开发者工具

各种已弃用的 API 已删除

我们已删除所有先前已弃用的 API。这些 API 在 React Navigation 6 中已弃用,并且在使用时会显示警告。因此,请确保在升级之前已解决所有警告。

已删除 API 的完整列表
  • @react-navigation/stack
    • 删除 mode 属性 - 请改用 presentation 选项
    • 删除 headerMode 属性 - 请改用 headerModeheaderShown 选项
    • 删除 keyboardHandlingEnabled 属性 - 请改用 keyboardHandlingEnabled 选项
  • @react-navigation/drawer
    • 删除 openByDefault 属性 - 请改用 defaultStatus 属性
    • 删除 lazy 属性 - 请改用 lazy 选项
    • 删除了包含以下选项的 drawerContentOptions 属性
      • drawerPosition - 请改用 drawerPosition 选项
      • drawerType - 请改用 drawerType 选项
      • edgeWidth - 请改用 swipeEdgeWidth 选项
      • hideStatusBar - 请改用 drawerHideStatusBarOnOpen 选项
      • keyboardDismissMode - 请改用 keyboardDismissMode 选项
      • minSwipeDistance - 请改用 swipeMinDistance 选项
      • overlayColor - 请改用 overlayColor 选项
      • statusBarAnimation - 请改用 drawerStatusBarAnimation 选项
      • gestureHandlerProps - 请改用 configureGestureHandler 选项
  • @react-navigation/bottom-tabs
    • 删除 lazy 属性 - 请改用 lazy 选项
    • 删除了包含以下选项的 tabBarOptions 属性
      • keyboardHidesTabBar - 请改用 tabBarHideOnKeyboard 选项
      • activeTintColor - 请改用 tabBarActiveTintColor 选项
      • inactiveTintColor - 请改用 tabBarInactiveTintColor 选项
      • activeBackgroundColor - 请改用 tabBarActiveBackgroundColor 选项
      • inactiveBackgroundColor - 请改用 tabBarInactiveBackgroundColor 选项
      • allowFontScaling - 请改用 tabBarAllowFontScaling 选项
      • showLabel - 请改用 tabBarShowLabel 选项
      • labelStyle - 请改用 tabBarLabelStyle 选项
      • iconStyle - 请改用 tabBarIconStyle 选项
      • tabStyle - 请使用 tabBarItemStyle 选项代替
      • labelPositionadapative - 请使用 tabBarLabelPosition 选项代替
      • tabBarVisible - 请使用 display: 'none' tabBarStyle 选项代替
  • @react-navigation/material-top-tabs
    • 移除 swipeEnabled 属性 - 请使用 swipeEnabled 选项代替
    • 删除 lazy 属性 - 请改用 lazy 选项
    • 移除 lazyPlaceholder 属性 - 请使用 lazyPlaceholder 选项代替
    • 移除 lazyPreloadDistance 属性 - 请使用 lazyPreloadDistance 选项代替
    • 移除包含以下选项的 tabBarOptions 属性: - renderBadge - 请使用 tabBarBadge 选项代替 - renderIndicator - 请使用 tabBarIndicator 选项代替 - activeTintColor - 请使用 tabBarActiveTintColor 选项代替 - inactiveTintColor - 请使用 tabBarInactiveTintColor 选项代替 - pressColor - 请使用 tabBarPressColor 选项代替 - pressOpacity - 请使用 tabBarPressOpacity 选项代替 - showLabel - 请使用 tabBarShowLabel 选项代替 - showIcon - 请使用 tabBarShowIcon 选项代替 - allowFontScaling - 请使用 tabBarAllowFontScaling 选项代替 - bounces - 请使用 tabBarBounces 选项代替 - scrollEnabled - 请使用 tabBarScrollEnabled 选项代替 - iconStyle - 请使用 tabBarIconStyle 选项代替 - labelStyle - 请使用 tabBarLabelStyle 选项代替 - tabStyle - 请使用 tabBarItemStyle 选项代替 - indicatorStyle - 请使用 tabBarIndicatorStyle 选项代替 - indicatorContainerStyle - 请使用 tabBarIndicatorContainerStyle 选项代替 - contentContainerStyle - 请使用 tabBarContentContainerStyle 选项代替 - style - 请使用 tabBarStyle 选项代替

其他

各种 UI 元素现在遵循 Material Design 3 指南

之前,React Navigation 中的 UI 元素,例如 iOS 以外平台上的 header、drawer、material top tabs 等,都遵循 Material Design 2 指南。我们现在已将它们更新为遵循 Material Design 3 指南。

React Native Tab View 现在有了一个新的 API 来指定各种选项

react-native-tab-view 中的 TabViewTabBar 组件的 API 已被修改。之前,TabBar 接受以下 props

  • getLabelText
  • getAccessible
  • getAccessibilityLabel
  • getTestID
  • renderIcon
  • renderLabel
  • renderBadge

这些 props 已被 TabView 上的 commonOptionsoptions props 替换

<TabView
commonOptions={{
icon: ({ route, focused, color }) => (
<Icon name={route.icon} color={color} />
),
}}
options={{
albums: {
labelText: 'Albums',
},
profile: {
labelText: 'Profile',
},
}}
/>

当使用自定义 tab bar 时,它将在参数中接收 options

新的 API 将使我们更容易提高库中 tab bar 项目的重新渲染性能。

请参阅 React Native Tab View 以了解用法。

自定义导航器现在需要更多类型信息

自定义导航器现在需要更多类型信息才能正确工作,以便我们在使用导航器时可以在 TypeScript 中提供更好的类型检查和自动完成。

export const createMyNavigator =  createNavigatorFactory<
MyNavigationState<ParamListBase>,
MyNavigationOptions,
MyNavigationEventMap,
typeof MyNavigator
>(MyNavigator);
export function createMyNavigator<
const ParamList extends ParamListBase,
const NavigatorID extends string | undefined = undefined,
const TypeBag extends NavigatorTypeBagBase = {
ParamList: ParamList;
NavigatorID: NavigatorID;
State: TabNavigationState<ParamList>;
ScreenOptions: TabNavigationOptions;
EventMap: TabNavigationEventMap;
NavigationList: {
[RouteName in keyof ParamList]: TabNavigationProp<
ParamList,
RouteName,
NavigatorID
>;
};
Navigator: typeof TabNavigator;
},
const Config extends StaticConfig<TypeBag> = StaticConfig<TypeBag>,
>(config?: Config): TypedNavigator<TypeBag, Config> {
return createNavigatorFactory(MyNavigator)(config);
}

请参阅 自定义导航器 以了解用法。

包现在使用 ESM 和包导出

React Navigation 中的所有包现在都使用 ESM 导出。虽然这不应影响大多数用户,但有一些更改需要注意

  • 如果您从包中导入内部文件,它们现在可能会受到您的 bundler 的限制,并且无法直接导入它们。您应该改用公共 API。
  • 如果您使用 patch-packageyarn patch 等修补包,则需要修补 lib/ 文件夹下的构建文件,而不是 src/ 下的源文件,因为源文件不再导出。
  • 如果您将 TypeScript 与 modulemoduleResolution 选项一起使用,则可能需要将 moduleResolution 设置为 Bundler 以匹配 Metro 的解析行为
  • 如果您使用 Webpack 来捆绑使用 React Navigation 的代码,则可能需要将 resolve.fullySpecified 设置为 false 才能使捆绑工作。

新功能

静态配置 API

React Navigation 5 引入了动态 API 以支持更灵活的用例。在 React Navigation 7 中,我们重新引入了静态配置 API

import { createNativeStackNavigator } from 'react-native-screens/native-stack';

const MyStack = createNativeStackNavigator({
screens: {
Home: {
screen: HomeScreen,
options: {
title: 'My App',
},
},
Details: {
screen: DetailsScreen,
linking: 'details/:id',
},
},
});

静态配置 API 提供了以下好处

  • 使用 TypeScript 进行更简单的类型检查:无需单独指定屏幕及其参数。有关更多详细信息,请参阅 使用 TypeScript 进行类型检查
  • 更轻松的深度链接设置:路径可以自动生成。链接配置可以在屏幕旁边定义以进行显式配置。有关更多详细信息,请参阅 配置链接

也可以混合使用静态和动态配置 API。例如,您可以将静态配置 API 用于顶层导航器,将动态配置 API 用于需要更高灵活性的嵌套导航器。

注意

静态配置 API 不会取代动态配置 API。两种 API 都得到同等支持,您可以选择更适合您的用例的 API。

您可以通过在示例中选择相应的选项卡来查看静态和动态配置 API 的示例。

转到 “Hello React Navigation” 以开始使用静态 API 编写一些代码。

改进的 TypeScript 支持

之前,在 optionslisteners 回调中接收到的 navigation 对象被类型化为 any,并且需要手动类型注释。现在,navigation 对象具有更准确的类型,该类型基于它所使用的导航器,并且不再需要类型注释。

我们还导出了一个新的 XOptionsArgs 类型(其中 X 是导航器名称,例如 StackOptionsArgsBottomTabOptionsArgs 等),该类型可用于键入 options 回调的参数。如果您想单独定义 options 回调,这将非常有用。

const options = ({
route,
}: StackOptionsArgs<RootStackParamList, 'Details'>) => {
return {
title: route.params.title,
};
};

改进的 RTL 支持

之前,各种 UI 元素使用 I18nManager API 来确定书写方向。但是,此 API 在 Web 上效果不佳,因为特定子树的书写方向可能不同,因此无法全局确定。

NavigationContainer 现在接受 direction 属性来指定布局方向,而不是依赖于 I18nManager API。它还通过 useLocale hook 公开此值,以便在您自己的组件中使用。

请参阅 navigation container 文档 以了解用法。

options 回调获取 theme

options 回调现在接收 theme 对象,以允许自定义 options 中指定的 UI 元素

<Stack.Screen
name="Details"
component={DetailsScreen}
options={({ theme }) => ({
headerRight: () => (
<IconButton
icon="dots-horizontal"
onPress={() => {}}
color={theme.colors.primary}
/>
),
})}
/>

请参阅 屏幕选项 以了解用法。

链接配置中的顶层 path

链接配置现在支持顶层 path 配置,以定义导航器中所有屏幕的基本路径

const linking = {
prefixes: ['https://mysite.com'],
config: {
path: 'app',
screens: {
Home: 'home',
Details: 'details/:id',
},
},
};

如果您的应用位于 Web 上的子路径下,这将非常有用。例如,如果您的应用位于 https://mysite.com/app 下,您可以将 path 定义为 app,并且可以在 https://mysite.com/app/details/42 访问 Details 屏幕。

请参阅 配置链接 以了解用法。

改进的 Web 集成

更多内置的触发导航的 UI 元素现在在 Web 上渲染 a 标签,以获得更好的可访问性和 SEO。这包括

  • header 中的返回按钮
  • material top tab 导航器中的 tab 按钮

诸如下方 tab bar 和 drawer 项目之类的 UI 元素已经在 Web 上渲染了 a 标签。

新的 usePreventRemove hook

之前,防止屏幕从堆栈中移除的唯一方法是使用 beforeRemove 事件。这在 Native Stack Navigator 中效果不佳。

新的 usePreventRemove hook 是 beforeRemove 的替代方案,它适用于 Native Stack Navigator。

请参阅 usePreventRemove 以了解用法。

新的 layout props

对于导航器

导航器现在支持 layout 属性。它可用于使用包装器增强导航器并添加额外的 UI。与添加常规包装器的区别在于,layout 回调中的代码可以访问导航器的状态、选项等。

<Stack.Navigator
layout={({ children, state, descriptors, navigation }) => (
<View style={styles.container}>
<Breadcrumbs />
{children}
</View>
)}
>
{/* ... */}
</Stack.Navigator>

请参阅 Navigator layout 以了解用法。

对于屏幕和组

layout 属性使为一组屏幕提供诸如全局错误边界和 suspense fallback 之类的东西变得更容易,而无需为每个屏幕单独手动添加 HOC。

它可以用于带有 layout 的单个屏幕

<Stack.Screen
name="MyScreen"
component={MyScreenComponent}
layout={({ children }) => (
<ErrorBoundary>
<React.Suspense
fallback={
<View style={styles.fallback}>
<Text style={styles.text}>Loading…</Text>
</View>
}
>
{children}
</React.Suspense>
</ErrorBoundary>
)}
/>

或带有 或带有 screenLayout导航器

<Stack.Group
screenLayout={({ children }) => (
<ErrorBoundary>
<React.Suspense
fallback={
<View style={styles.fallback}>
<Text style={styles.text}>Loading…</Text>
</View>
}
>
{children}
</React.Suspense>
</ErrorBoundary>
)}
>
{/* screens */}
</Stack.Group>

预加载屏幕

所有内置导航器现在都支持在导航到屏幕之前预加载屏幕。这有助于通过预加载用户可能接下来导航到的屏幕来提高应用的感知性能。预加载屏幕将在屏幕外渲染它并执行其副作用,例如数据获取。

要预加载屏幕,您可以使用 navigation 对象上的 preload 方法

navigation.preload('Details', { id: 42 });

请参阅 preload 以了解用法。

导航器的改进

底部 Tab 导航器现在可以在侧面和顶部显示选项卡

@react-navigation/bottom-tabs 包现在支持在侧面显示选项卡。这将使构建响应式 UI 变得更容易,您可以在较小的屏幕上在底部显示选项卡,并在较大的屏幕上切换到侧边栏。

类似地,也支持在顶部显示选项卡,这对于 Android TV 或 Apple TV 应用可能很有用。

您可以使用 tabBarPosition 选项来自定义选项卡的位置

<Tab.Navigator
screenOptions={{
tabBarPosition: 'left',
}}
>
{/* ... */}
</Tab.Navigator>

请参阅 底部 Tab 导航器选项 以了解用法。

底部 Tab 导航器现在支持动画

@react-navigation/bottom-tabs 包现在支持动画。这是我们在 Canny 板上最需要的功能之一:TabNavigator 自定义过渡

您可以使用 animation 选项来自定义 tab 过渡的动画

<Tab.Navigator
screenOptions={{
animation: 'fade',
}}
>
{/* ... */}
</Tab.Navigator>

请参阅 底部 Tab 导航器动画 以了解用法。

Stack 导航器现在支持 animation 选项

@react-navigation/stack 包现在支持 animation 选项,以自定义屏幕过渡的动画

<Stack.Navigator
screenOptions={{
animation: 'slide_from_right',
}}
>
{/* ... */}
</Stack.Navigator>

animation 选项是 TransitionPresets API 的替代方案,旨在使在 JS stack 和 native stack 导航器之间迁移更容易。

有关用法,请参阅 堆栈导航器动画

Native Stack 导航器现在导出一个 useAnimatedHeaderHeight hook

@react-navigation/native-stack 包现在导出一个 useAnimatedHeaderHeight hook。它可用于根据 header 高度变化来动画化内容 - 例如当 iOS 上的大标题缩小为小标题时

const headerHeight = useAnimatedHeaderHeight();

return (
<Animated.View style={{ transform: { translateY: headerHeight } }}>
{/* ... */}
</Animated.View>
);

所有带有 header 的导航器现在都支持 headerSearchBarOptions

来自 @react-navigation/elementsHeader 组件现在支持 headerSearchBarOptions 属性。这意味着所有使用 Header 组件的导航器现在在所有平台上也都支持 header 中的搜索栏。以前,这仅在 iOS 和 Android 上的 Native Stack Navigator 中可用。

React.useLayoutEffect(() => {
navigation.setOptions({
headerSearchBarOptions: {
placeholder: 'Search',
onChangeText: (text) => {
// Do something
},
},
});
}, [navigation]);

请参阅 headerSearchBarOptions 以了解用法。

elements 库中的新组件

@react-navigation/elements 包现在包含可以在您的应用中使用的新组件

Button

Button 组件内置了对导航到屏幕的支持,并在 Web 上用于导航时渲染 anchor 标签

<Button screen="Profile" params={{ userId: 'jane' }}>
View Jane's Profile
<Button>

它也可以用作常规按钮

<Button
onPress={() => {
/* do something */
}}
>
Do something
</Button>

该按钮遵循 Material Design 3 指南

请参阅 Button 以了解用法。

HeaderButton

HeaderButton 组件可用于在 header 中渲染带有适当样式的按钮

headerRight: ({ tintColor }) => (
<HeaderButton
accessibilityLabel="More options"
onPress={() => {
/* do something */
}}
>
<MaterialCommunityIcons
name="dots-horizontal-circle-outline"
size={24}
color={tintColor}
/>
</HeaderButton>
),

请参阅 HeaderButton 以了解用法。

Label

Label 组件可用于渲染标签文本,例如 tab bar 按钮中的标签

<Label>Home</Label>

请参阅 Label 以了解用法。

react-native-drawer-layout

@react-navigation/drawer 中使用的 drawer 实现现在作为一个名为 react-native-drawer-layout 的独立包提供。这使得即使您不使用 React Navigation,或者您想在没有导航器的情况下使用它,也更容易使用 drawer 实现。

您可以使用以下命令安装它

npm install react-native-drawer-layout

请参阅 react-native-drawer-layout 以了解用法。

useLogger 开发工具

@react-navigation/devtools 包现在导出一个 useLogger hook。它可用于将导航操作记录到控制台

请参阅 useLogger 以了解用法。