React Navigation 官网:reactnavigation.org/
1. 准备工作
1.1 最低要求
React Navigation 6
要求 react-native 版本至少 0.63.0
。
1.2 安装依赖
在 React Native
项目中安装所需的软件包:
yarn add @react-navigation/native@next
还需要安装 react-native-gesture-handler 、react-native-reanimated、react-native-screens、react-native-safe-area-context。
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context
1.2.1
如果是在 mac 上开发 iOS 项目,需要安装 CocoaPods
来完成项目链接:
npx pod-install ios
1.2.2 react-native-screens
react-native-screens
在 Android 需要修改 android/app/src/main/java/<your package name>/MainActivity.java
文件 。
在 MainActivity class 添加以下代码:
import android.os.Bundle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
1.2.3 react-native-gesture-handler
react-native-gesture-handler
在 Android 也需要修改 android/app/src/main/java/<your package name>/MainActivity.java
文件 。
package com.swmansion.gesturehandler.react.example;
import com.facebook.react.ReactActivity;
+ import com.facebook.react.ReactActivityDelegate;
+ import com.facebook.react.ReactRootView;
+ import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "Example";
}
+ @Override
+ protected ReactActivityDelegate createReactActivityDelegate() {
+ return new ReactActivityDelegate(this, getMainComponentName()) {
+ @Override
+ protected ReactRootView createRootView() {
+ return new RNGestureHandlerEnabledRootView(MainActivity.this);
+ }
+ };
+ }
}
完成了 react-native-gesture-handler
的安装,在项目的入口文件(例如 index.js
或App.js
)引入 react-native-gesture-handler(确保在入口文件的第一行)
注意:如果您忽略这一步,尽管在开发中运行是正常的,但在生产上将会奔溃。
import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
export default function App() {
return (
<NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
);
}
1.3 Hello React Navigation
安装堆栈导航库
yarn add @react-navigation/native-stack@next
注意 @react-navigation/native-stack 依赖于 react-native-screens 库
createStackNavigator
函数返回一个包含两个属性的对象: 屏幕
和 导航器
。它们都是用于配置导航器的 React 组件。导航器应该将屏幕元素作为子元素来定义路由的配置。
NavigationContainer
是一个管理导航树并包含导航状态的组件。该组件必须包装所有导航器结构。通常,我们会将这个组件呈现在应用程序的根目录下,这个根目录通常是从 app .js 导出的组件。这里我自定义了一个路由文件,然后在app.js 中引入:
import 'react-native-gesture-handler';
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
路由的名称的对大小写不敏感——您可以使用小写的 home 或大写的 home。但是一般路由名称用大写。
1.3.1 指定 options
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Overview' }}
/>
1.3.2 传递 props
<Stack.Screen name="Home">
{props => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
React Navigation 使用指南
Tab navigation
安装依赖
:
yarn add @react-navigation/bottom-tabs@next
示例
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import IconFont from '../src/iconfont';
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
console.log('color: ', color);
if (route.name === 'Home') {
return <IconFont name="iconshouye" size={size} color={color} />;
} else if (route.name === 'Settings') {
return <IconFont name="iconshezhi1" size={size} color={color} />;
}
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}>
<Tab.Screen name="Home" component={HomeScreen} options={{ tabBarBadge: 3 }} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
-
tabBarActiveTintColor
表示TabBarIcon
选中颜色,tabBarInactiveTintColor
表示未选中颜色。 -
tabBarBadge
<Tab.Screen
name="Home"
component={HomeScreen}
options={{ tabBarBadge: 3 }}
/>
Drawer navigation
安装依赖
:
yarn add @react-navigation/drawer@next
示例
import 'react-native-gesture-handler';
import * as React from 'react';
import { View, Button, Text, Image, Alert } from 'react-native';
import { NavigationContainer, DrawerActions } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '@react-navigation/drawer';
function Feed({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Feed Screen</Text>
<Button title="Open drawer" onPress={() => navigation.openDrawer()} />
<Button
title="Toggle drawer"
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
/>
</View>
);
}
function Notifications() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Notifications Screen</Text>
</View>
);
}
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
label="Close drawer"
onPress={() => props.navigation.closeDrawer()}
/>
<DrawerItem
label="Toggle drawer"
onPress={() => props.navigation.toggleDrawer()}
/>
</DrawerContentScrollView>
);
}
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Feed" component={Feed} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
);
}
切换 Drawer
的方式:
-
navigation.openDrawer()
、navigation.closeDrawer()
; -
navigation.
toggleDrawer()
; -
navigation.dispatch(
DrawerActions
.openDrawer())、navigation.dispatch(DrawerActions.closeDrawer())、navigation.dispatch(DrawerActions.toggleDrawer());
刘海屏
React Native 处理刘海屏问题需要用到 react-native-safe-area-context 这个库。
- 当渲染没有 header 导航或者 tabBar 导航时
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
function Demo() {
return (
<View
style={{
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
}}>
<Text>This is top text.</Text>
<Text>This is bottom text.</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home">
{() => (
<Tab.Navigator
initialRouteName="Analitics"
tabBar={() => null}
screenOptions={{ headerShown: false }}>
<Tab.Screen name="Analitics" component={Demo} />
<Tab.Screen name="Profile" component={Demo} />
</Tab.Navigator>
)}
</Stack.Screen>
<Stack.Screen name="Settings" component={Demo} />
</Stack.Navigator>
</NavigationContainer>
);
}
- 使用
react-native-safe-area-context
import * as React from 'react';
import { Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
function Demo() {
return (
<SafeAreaView
style={{
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
}}>
<Text>This is top text.</Text>
<Text>This is bottom text.</Text>
</SafeAreaView>
);
}
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home">
{() => (
<Tab.Navigator
initialRouteName="Analitics"
tabBar={() => null}
screenOptions={{ headerShown: false }}>
<Tab.Screen name="Analitics" component={Demo} />
<Tab.Screen name="Profile" component={Demo} />
</Tab.Navigator>
)}
</Stack.Screen>
<Stack.Screen name="Settings" component={Demo} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
}
使用 hook 方式
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import {
SafeAreaProvider,
useSafeAreaInsets,
} from 'react-native-safe-area-context';
function Demo() {
const insets = useSafeAreaInsets();
return (
<View
style={{
paddingTop: insets.top,
// paddingBottom: insets.bottom,
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
}}>
<Text>This is top text.</Text>
<Text>This is bottom text.</Text>
</View>
);
}
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home">
{() => (
<Tab.Navigator
initialRouteName="Analitics"
tabBar={() => null}
screenOptions={{ headerShown: false }}>
<Tab.Screen name="Analitics" component={Demo} />
<Tab.Screen name="Profile" component={Demo} />
</Tab.Navigator>
)}
</Stack.Screen>
<Stack.Screen name="Settings" component={Demo} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
}
重点代码:
const insets = useSafeAreaInsets()
style={{paddingTop: insets.top,... }}
基于路由的不同状态栏配置
如果您没有导航标题,或者您的导航标题根据路线更改颜色,您需要确保为内容使用正确的颜色。
堆栈导航
import * as React from 'react';
import { Text, StatusBar, Button, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
function Screen1({ navigation }) {
return (
<SafeAreaView style={[styles.container, { backgroundColor: '#6a51ae' }]}>
<StatusBar barStyle="light-content" backgroundColor="#6a51ae" />
<Text style={{ color: '#fff' }}>Light Screen</Text>
<Button
title="Next screen"
onPress={() => navigation.navigate('Screen2')}
/>
</SafeAreaView>
);
}
function Screen2({ navigation }) {
return (
<SafeAreaView style={[styles.container, { backgroundColor: '#ecf0f1' }]}>
<StatusBar barStyle="dark-content" backgroundColor="#ecf0f1" />
<Text>Dark Screen</Text>
<Button
title="Next screen"
onPress={() => navigation.navigate('Screen1')}
/>
</SafeAreaView>
);
}
const Stack = createNativeStackNavigator();
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Screen1" component={Screen1} />
<Stack.Screen name="Screen2" component={Screen2} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
});
标签导航和抽屉导航
如果您使用选项卡或抽屉导航器,则它会更复杂一些,StatusBar
配置可能会被覆盖。
为了解决这个问题,我们必须让状态栏组件知道屏幕焦点并仅在屏幕聚焦时才渲染它。 我们可以通过使用 useIsFocused
钩子并创建一个包装组件来实现这一点。
import * as React from 'react';
import { StatusBar } from 'react-native';
import { useIsFocused } from '@react-navigation/native';
function FocusAwareStatusBar(props) {
const isFocused = useIsFocused();
return isFocused ? <StatusBar {...props} /> : null;
}
此时屏幕 Screen1.js
和 Screen2.js
将使用 FocusAwareStatusBar
组件而不是 React Native 的 StatusBar 组件。
function Screen1({ navigation }) {
return (
<SafeAreaView style={[styles.container, { backgroundColor: '#6a51ae' }]}>
<FocusAwareStatusBar barStyle="light-content" backgroundColor="#6a51ae" />
<Text style={{ color: '#fff' }}>Light Screen</Text>
<Button
title="Next screen"
onPress={() => navigation.navigate('Screen2')}
color="#fff"
/>
</SafeAreaView>
);
}
function Screen2({ navigation }) {
return (
<SafeAreaView style={[styles.container, { backgroundColor: '#ecf0f1' }]}>
<FocusAwareStatusBar barStyle="dark-content" backgroundColor="#ecf0f1" />
<Text>Dark Screen</Text>
<Button
title="Next screen"
onPress={() => navigation.navigate('Screen1')}
/>
</SafeAreaView>
);
}
监听屏幕聚焦
navigation.addListener
import * as React from 'react';
import { View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function ProfileScreen({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
alert('Screen is focused');
});
// Return the function to unsubscribe from the event so it gets removed on unmount
return unsubscribe;
}, []);
return <View />;
}
function HomeScreen() {
return <View />;
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
useFocusEffect
import * as React from 'react';
import { View } from 'react-native';
import { NavigationContainer, useFocusEffect } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function ProfileScreen() {
useFocusEffect(
React.useCallback(() => {
alert('Screen was focused');
// Do something when the screen is focused
return () => {
alert('Screen was unfocused');
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, []),
);
return <View />;
}
function HomeScreen() {
return <View />;
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
useIsFocused
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer, useIsFocused } from '@react-navigation/native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
function ProfileScreen() {
// This hook returns `true` if the screen is focused, `false` otherwise
const isFocused = useIsFocused();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{isFocused ? 'focused' : 'unfocused'}</Text>
</View>
);
}
function HomeScreen() {
return <View />;
}
const Tab = createMaterialTopTabNavigator();
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>
<Tab.Navigator tabBarPosition="top" style={{ marginTop: 24 }}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
}
任意组件访问导航
useNavigation
import * as React from 'react';
import { Button } from 'react-native';
import { useNavigation } from '@react-navigation/native';
function GoToButton({ screenName }) {
const navigation = useNavigation();
return (
<Button
title={`Go to ${screenName}`}
onPress={() => navigation.navigate(screenName)}
/>
);
}
在没有 navigation prop 的情况下导航跳转
有时需要从无法访问 navigation prop
的地方触发导航操作,例如 Redux
中间件。 对于这种情况,可以从导航容器调度导航操作。
如果从组件内部导航无需向下传递导航的方法,可以用 useNavigation
。如果导航需要向下传递的话,可以通过 ref 访问根导航对象并将其传递给我们稍后将用于导航的 RootNavigation
。
// App.js
import { NavigationContainer } from '@react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
// RootNavigation.js
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef()
export function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
还可以添加其他导航操作:
import { StackActions } from '@react-navigation/native';
// ...
export function push(...args) {
if (navigationRef.isReady()) {
navigationRef.dispatch(StackActions.push(...args));
}
}
举一个例子
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import {
NavigationContainer,
createNavigationContainerRef,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const navigationRef = createNavigationContainerRef();
function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
function Home() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Go to Settings"
onPress={() => navigate('Settings', { userName: 'Lucy' })}
/>
</View>
);
}
function Settings({ route }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello {route.params.userName}</Text>
<Button title="Go to Home" onPress={() => navigate('Home')} />
</View>
);
}
const RootStack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer ref={navigationRef}>
<RootStack.Navigator>
<RootStack.Screen name="Home" component={Home} />
<RootStack.Screen name="Settings" component={Settings} />
</RootStack.Navigator>
</NavigationContainer>
);
}
React Navigation TypeScript
navigator
要对我们的路由名称
和参数
进行类型检查,我们需要做的第一件事是创建一个对象类型,其中包含路由名称到路由参数的映射。 例如,假设我们在根导航器中有一个名为 Profile 的路由,它应该有一个参数 userId:
type RootStackParamList = {
Profile: { userId: string };
};
同样,我们需要对每条路线做同样的事情:
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Feed: { sort: 'latest' | 'top' } | undefined;
};
指定 undefined
意味着路由没有参数。
定义映射后,我们需要告诉导航器使用它。 为此,我们可以将其作为泛型传递给 createXNavigator
函数:
import { createStackNavigator } from '@react-navigation/stack';
const RootStack = createStackNavigator<RootStackParamList>();
使用
<RootStack.Navigator initialRouteName="Home">
<RootStack.Screen name="Home" component={Home} />
<RootStack.Screen
name="Profile"
component={Profile}
initialParams={{ userId: user.id }}
/>
<RootStack.Screen name="Feed" component={Feed} />
</RootStack.Navigator>
screens
import { NativeStackScreenProps } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Feed: { sort: 'latest' | 'top' } | undefined;
};
type Props = NativeStackScreenProps<RootStackParamList, 'Profile'>;
NativeStackScreenProps
需要 2 个泛型,我们之前定义的 param
列表对象,以及当前路由的名称
。
同样的,可以导入 StackScreenProps
for @react-navigation/stack
、DrawerScreenProps
from @react-navigation/drawer
、BottomTabScreenProps
from @react-navigation/bottom-tabs
等等。
对于 function components
:
function ProfileScreen({ route, navigation }: Props) {
// ...
}
对于 class components
:
class ProfileScreen extends React.Component<Props> {
render() {
// ...
}
}
可以从 Props 类型中获取 navigation
和 route
的类型:
type ProfileScreenNavigationProp = Props['navigation'];
type ProfileScreenRouteProp = Props['route'];
或者也可以分别定义 navigation
和 route
的 props 。
- 对于
navigation props
来说, 要获取navigation
的类型,我们需要从导航器中导入相应的类型。
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
type ProfileScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'Profile'
>;
同样的,你也可以导入 import { StackNavigationProp } from '@react-navigation/stack'
、import { DrawerNavigationProp } from '@react-navigation/drawer'
、import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs'
- 对于
route
prop ,我们需要使用@react-navigation/native
中的RouteProp
类型。
import { RouteProp } from '@react-navigation/native';
type ProfileScreenRouteProp = RouteProp<RootStackParamList, 'Profile'>;
嵌套导航
在嵌套导航器中检查 screens 和 params
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
在上面的嵌套导航中,可以通过传递嵌套屏幕的 screen 和 params 属性来导航到嵌套导航中的屏幕。
navigation.navigate('Home', {
screen: 'Feed',
params: { sort: 'latest' },
});
为了能够进行类型检查,我们需要从包含嵌套导航的屏幕中提取参数。 这可以使用 NavigatorScreenParams
。
import { NavigatorScreenParams } from '@react-navigation/native';
type TabParamList = {
Home: NavigatorScreenParams<StackParamList>;
Profile: { userId: string };
};
组合导航
嵌套导航器时,屏幕的导航道具是多个导航道具的组合。 例如,如果我们在堆栈中有一个选项卡,则导航属性将同时具有 jumpTo(来自选项卡导航器)和 push(来自堆栈导航器)。 为了更容易地组合来自多个导航器的类型,您可以使用 CompositeScreenProps
类型。
import { CompositeScreenProps } from '@react-navigation/native';
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
import { StackScreenProps } from '@react-navigation/stack';
type ProfileScreenNavigationProp = CompositeScreenProps<
BottomTabScreenProps<TabParamList, 'Profile'>,
StackScreenProps<StackParamList>
>;
对于多个父导航器,应嵌套此辅助类型:
type ProfileScreenNavigationProp = CompositeScreenProps<
BottomTabScreenProps<TabParamList, 'Profile'>,
CompositeScreenProps<
StackScreenProps<StackParamList>,
DrawerScreenProps<DrawerParamList>
>
>;
如果单独注释 navigation
,则可以改用 CompositeNavigationProp
。 用法类似于 CompositeScreenProps:
import { CompositeNavigationProp } from '@react-navigation/native';
import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
import { StackNavigationProp } from '@react-navigation/stack';
type ProfileScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Profile'>,
StackNavigationProp<StackParamList>
>;
声明 useNavigation
const navigation = useNavigation<ProfileScreenNavigationProp>();
声明 useRoute
const route = useRoute<ProfileScreenRouteProp>();
声明 options、screenOptions
import { StackNavigationOptions } from '@react-navigation/stack';
const options: StackNavigationOptions = {
headerShown: false,
};
同样的,你也可以导入 import { DrawerNavigationOptions } from '@react-navigation/drawer'、import { BottomTabNavigationOptions } from '@react-navigation/bottom-tabs'
等等。
声明 ref、NavigationContainer
createNavigationContainerRef
如果使用 createNavigationContainerRef() 方法创建 ref,则可以通过以下方式进行类型检查:
import { createNavigationContainerRef } from '@react-navigation/native';
// ...
const navigationRef = createNavigationContainerRef<RootStackParamList>();
useNavigationContainerRef
import { createNavigationContainerRef } from '@react-navigation/native';
// ...
const navigationRef = useNavigationContainerRef<RootStackParamList>();
useRef
import { NavigationContainerRef } from '@react-navigation/native';
// ...
const navigationRef = React.useRef<NavigationContainerRef<RootStackParamList>>(null);
createRef
import { NavigationContainerRef } from '@react-navigation/native';
// ...
const navigationRef = React.createRef<NavigationContainerRef<RootStackParamList>>();
React Navigation 几个重要 API
Group
Group
组件用于在导航器内对多个屏幕进行分组。
const Stack = createStackNavigator(); // Stack contains Screen & Navigator properties
<Stack.Navigator>
<Stack.Group
screenOptions={{ headerStyle: { backgroundColor: 'papayawhip' } }}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Group>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Search" component={SearchScreen} />
<Stack.Screen name="Share" component={ShareScreen} />
</Stack.Group>
</Stack.Navigator>
Props
screenOptions
<Stack.Group
screenOptions={{
presentation: 'modal',
}}
>
{/* screens */}
</Stack.Group>
<Stack.Group
screenOptions={({ route, navigation }) => ({
title: route.params.title,
})}
>
{/* screens */}
</Stack.Group>
Screen
const Stack = createNativeStackNavigator(); // Stack contains Screen & Navigator properties
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
Props
name
<Stack.Screen name="Profile" component={ProfileScreen} />
name
用于跳转到 Screen
:
navigation.navigate('Profile');
options
options
用于配置屏幕在导航器中的显示方式的选项, 它接受一个对象或一个返回一个对象的函数。
- 接受一个对象
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={{
title: 'Awesome app',
}}
/>
- 接受一个返回一个对象的函数
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={({ route, navigation }) => ({
title: route.params.userId,
})}
/>
initialParams
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
getId
<Stack.Screen
name="Profile"
component={ProfileScreen}
getId={({ params }) => params.userId}
/>
component
<Stack.Screen name="Profile" component={ProfileScreen} />
getComponent
<Stack.Screen
name="Profile"
getComponent={() => require('./ProfileScreen').default}
/>
children
<Stack.Screen name="Profile">
{(props) => <ProfileScreen {...props} />}
</Stack.Screen>
Route prop
key
屏幕的唯一键, 导航到此屏幕时自动创建或添加。
name
屏幕名称。
path
当通过 deep link
打开屏幕时,打开屏幕的路径的可选字符串。
params
包含在导航时定义的参数的可选对象,例如 navigate('Twitter', { user: 'Dan Abramov' })
。
function ProfileScreen({ route }) {
return (
<View>
<Text>This is the profile screen of the app</Text>
<Text>{route.name}</Text>
</View>
);
}