名称: react-native-navigation 用户可调用: false 描述: 在使用 React Navigation 在 React Native 应用中实现导航时使用。涵盖堆栈导航、标签导航、抽屉导航、深度链接和导航模式。 允许工具:
- 读取
- 写入
- 编辑
- Bash
- Grep
- Glob
React Native 导航
在使用 React Navigation(事实上的标准导航库)在 React Native 应用程序中实现导航时使用此技能。
关键概念
安装
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context
# 对于堆栈导航
npm install @react-navigation/native-stack
# 对于标签导航
npm install @react-navigation/bottom-tabs
# 对于抽屉导航
npm install @react-navigation/drawer react-native-gesture-handler react-native-reanimated
基本设置
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Details: { itemId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
堆栈导航
最常见的导航模式:
import React from 'react';
import { View, Text, Button } from 'react-native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Details: { itemId: string; title: string };
};
type HomeProps = NativeStackScreenProps<RootStackParamList, 'Home'>;
type DetailsProps = NativeStackScreenProps<RootStackParamList, 'Details'>;
function HomeScreen({ navigation }: HomeProps) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>首页</Text>
<Button
title="前往详情"
onPress={() =>
navigation.navigate('Details', {
itemId: '123',
title: '我的项目',
})
}
/>
</View>
);
}
function DetailsScreen({ route, navigation }: DetailsProps) {
const { itemId, title } = route.params;
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>详情页面</Text>
<Text>项目ID: {itemId}</Text>
<Text>标题: {title}</Text>
<Button title="返回" onPress={() => navigation.goBack()} />
</View>
);
}
标签导航
底部标签用于主要导航:
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
type TabParamList = {
Home: undefined;
Search: undefined;
Profile: undefined;
};
const Tab = createBottomTabNavigator<TabParamList>();
export default function TabNavigator() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName: keyof typeof Ionicons.glyphMap;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'Search') {
iconName = focused ? 'search' : 'search-outline';
} else {
iconName = focused ? 'person' : 'person-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: '#007AFF',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Search" component={SearchScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
最佳实践
类型安全导航
定义导航类型以实现类型安全:
import { NativeStackScreenProps } from '@react-navigation/native-stack';
// 定义参数列表
type RootStackParamList = {
Home: undefined;
Details: { itemId: string };
UserProfile: { userId: string; name: string };
};
// 声明全局类型
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
// 使用类型化属性
type DetailsProps = NativeStackScreenProps<RootStackParamList, 'Details'>;
function DetailsScreen({ route, navigation }: DetailsProps) {
// route.params 完全类型化
const { itemId } = route.params;
// navigation.navigate 类型安全
navigation.navigate('UserProfile', {
userId: '123',
name: 'John',
});
return <View />;
}
标题自定义
自定义导航标题:
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#007AFF',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: '我的首页',
headerRight: () => (
<Button
onPress={() => console.log('Pressed')}
title="信息"
color="#fff"
/>
),
}}
/>
</Stack.Navigator>
动态标题选项
从屏幕设置标题选项:
import { useLayoutEffect } from 'react';
function DetailsScreen({ navigation, route }: DetailsProps) {
useLayoutEffect(() => {
navigation.setOptions({
title: route.params.title,
headerRight: () => (
<Button title="保存" onPress={() => console.log('保存')} />
),
});
}, [navigation, route.params.title]);
return <View />;
}
嵌套导航器
组合不同导航模式:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const HomeStack = createNativeStackNavigator();
const ProfileStack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
function ProfileStackScreen() {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileScreen} />
<ProfileStack.Screen name="Settings" component={SettingsScreen} />
</ProfileStack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="HomeTab" component={HomeStackScreen} />
<Tab.Screen name="ProfileTab" component={ProfileStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
常见模式
认证流程
import React, { useState } from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
SignIn: undefined;
SignUp: undefined;
Home: undefined;
Details: { itemId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
const [isSignedIn, setIsSignedIn] = useState(false);
return (
<NavigationContainer>
<Stack.Navigator>
{!isSignedIn ? (
// 认证页面
<>
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
</>
) : (
// 应用页面
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
);
}
深度链接
配置深度链接:
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['myapp://', 'https://myapp.com'],
config: {
screens: {
Home: 'home',
Details: 'details/:itemId',
UserProfile: 'user/:userId',
},
},
};
export default function App() {
return (
<NavigationContainer linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="UserProfile" component={UserProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
模态导航
以模态形式呈现页面:
<Stack.Navigator>
<Stack.Group>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Group>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="CreatePost" component={CreatePostScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Group>
</Stack.Navigator>
导航守卫
使用守卫保护路由:
import { useEffect } from 'react';
function ProtectedScreen({ navigation }: any) {
const isAuthenticated = useAuth(); // 自定义钩子
useEffect(() => {
if (!isAuthenticated) {
navigation.replace('SignIn');
}
}, [isAuthenticated, navigation]);
if (!isAuthenticated) {
return null; // 或加载页面
}
return <View>{/* 受保护内容 */}</View>;
}
自定义标签栏
创建自定义标签栏:
import { View, Text, TouchableOpacity } from 'react-native';
function CustomTabBar({ state, descriptors, navigation }: any) {
return (
<View style={{ flexDirection: 'row', height: 60 }}>
{state.routes.map((route: any, index: number) => {
const { options } = descriptors[route.key];
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
return (
<TouchableOpacity
key={route.key}
onPress={onPress}
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: isFocused ? '#007AFF' : '#fff',
}}
>
<Text style={{ color: isFocused ? '#fff' : '#000' }}>
{options.title || route.name}
</Text>
</TouchableOpacity>
);
})}
</View>
);
}
<Tab.Navigator tabBar={(props) => <CustomTabBar {...props} />}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
反模式
不要在 useEffect 中没有依赖项时导航
// 错误 - 无限循环风险
useEffect(() => {
navigation.navigate('Home');
});
// 正确 - 适当的依赖项
useEffect(() => {
if (shouldNavigate) {
navigation.navigate('Home');
}
}, [shouldNavigate, navigation]);
不要使用 navigate() 来替换页面
// 错误 - 添加到导航堆栈
navigation.navigate('SignIn');
// 正确 - 替换当前页面
navigation.replace('SignIn');
不要在没有类型安全的情况下访问导航
// 错误 - 没有类型安全
function MyScreen({ navigation }: any) {
navigation.navigate('Detials', { itemId: 123 }); // 拼写错误不会被捕获
}
// 正确 - 类型安全导航
type Props = NativeStackScreenProps<RootStackParamList, 'Home'>;
function MyScreen({ navigation }: Props) {
navigation.navigate('Details', { itemId: '123' }); // 类型检查
}
不要忘记在 Android 上处理返回按钮
import { useEffect } from 'react';
import { BackHandler } from 'react-native';
function MyScreen({ navigation }: any) {
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
() => {
navigation.goBack();
return true; // 阻止默认行为
}
);
return () => backHandler.remove();
}, [navigation]);
return <View />;
}
相关技能
- react-native-components: 为页面构建 UI 组件
- react-native-platform: 平台特定的导航行为
- react-native-performance: 优化导航性能