从 6.x 版本升级
React Navigation 7 专注于简化 API,以避免可能导致错误的模式。这意味着弃用一些为了向后兼容性而保留的遗留行为。
本指南列出了从 React Navigation 6 升级到 React Navigation 7 时需要注意的所有重大更改和新功能。
最低要求
react-native
>= 0.72.0expo
>= 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
内有条件地渲染其导航器,则可能并非如此。
了解这一点很重要,因为如果没有渲染导航器,我们将无法调度任何导航操作,因为没有导航器来处理它们。但是 onReady
和 navigationRef.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 现在使用屏幕名称而不是路径
以前,Link
组件和 useLinkProps
hook 被设计为通过 to
属性与路径字符串一起使用。但这有一些问题
- 路径字符串不是类型安全的,在重构后很容易导致拼写错误和错误
- 即使屏幕名称是首选方法,API 也使得通过屏幕名称进行导航更加不方便
现在,它们不再接受接受路径字符串的 to
属性,而是接受 screen
和 params
属性,以及可选的 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
组件时,您现在将具有完全的类型安全性。
有关用法,请参阅 Link
和 useLinkProps
。
useLinkBuilder
hook 现在返回一个对象而不是一个函数
以前,useLinkBuilder
hook 返回一个函数来为屏幕构建 href
- 这主要用于构建自定义导航器。现在,它返回一个带有 buildHref
和 buildAction
方法的对象
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
设置为 default
和 minimal
来实现以前的行为,以显示和隐藏后退按钮标题
<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 resolutions 或 npm 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
已被删除,取而代之的是 headerLeft
和 HeaderBackButton
元素中的 displayMode
以前,可以使用 labelVisible
来控制是否在标题中显示后退按钮标题。它现在已被删除,取而代之的是提供更多灵活性的 displayMode
。
新的可能值是
default
:根据可用空间显示以下内容之一:上一个屏幕的标题、通用标题(例如“返回”)或无标题(仅图标)。generic
:根据可用空间显示以下内容之一:通用标题(例如“返回”)或无标题(仅图标)。仅限 iOS >= 14,在旧版本 iOS 上回退到“default”。minimal
:始终仅显示图标,不带标题。
可以通过分别将 displayMode
设置为 default
或 generic
来显示和将 minimal
设置为隐藏后退按钮标题来实现以前的行为
<HeaderBackButton
labelVisible={false}
displayMode="minimal"
/>
弃用和删除
Material Bottom Tab Navigator 现在位于 react-native-paper
软件包中
@react-navigation/material-bottom-tabs
软件包为 react-native-paper
的 BottomNavigation
组件提供了 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
属性 - 请改用headerMode
和headerShown
选项 - 删除
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
选项代替labelPosition
和adapative
- 请使用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
中的 TabView
和 TabBar
组件的 API 已被修改。之前,TabBar
接受以下 props
getLabelText
getAccessible
getAccessibilityLabel
getTestID
renderIcon
renderLabel
renderBadge
这些 props 已被 TabView
上的 commonOptions
和 options
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-package
、yarn patch
等修补包,则需要修补lib/
文件夹下的构建文件,而不是src/
下的源文件,因为源文件不再导出。 - 如果您将 TypeScript 与
module
或moduleResolution
选项一起使用,则可能需要将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 支持
之前,在 options
和 listeners
回调中接收到的 navigation
对象被类型化为 any
,并且需要手动类型注释。现在,navigation
对象具有更准确的类型,该类型基于它所使用的导航器,并且不再需要类型注释。
我们还导出了一个新的 XOptionsArgs
类型(其中 X
是导航器名称,例如 StackOptionsArgs
、BottomTabOptionsArgs
等),该类型可用于键入 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>
)}
/>
<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/elements
的 Header
组件现在支持 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
- Yarn
- pnpm
npm install react-native-drawer-layout
yarn add react-native-drawer-layout
pnpm add react-native-drawer-layout
请参阅 react-native-drawer-layout
以了解用法。
useLogger
开发工具
@react-navigation/devtools
包现在导出一个 useLogger
hook。它可用于将导航操作记录到控制台
请参阅 useLogger
以了解用法。