React Navigation导航进阶 #
概述 #
本章节介绍 React Navigation 的高级功能,包括参数传递、深层链接、导航状态管理和自定义导航器。
参数传递 #
传递复杂参数 #
tsx
import React from 'react';
import {View, Button} from 'react-native';
type Product = {
id: string;
name: string;
price: number;
description: string;
};
const ProductListScreen = ({navigation}) => {
const product: Product = {
id: '1',
name: 'iPhone 15',
price: 999,
description: 'Latest iPhone model',
};
return (
<View>
<Button
title="View Details"
onPress={() =>
navigation.navigate('ProductDetails', {
product,
from: 'ProductList',
})
}
/>
</View>
);
};
使用 TypeScript 类型 #
tsx
import React from 'react';
import {View, Text} from 'react-native';
import {NativeStackScreenProps} from '@react-navigation/native-stack';
type RootStackParamList = {
ProductList: undefined;
ProductDetails: {
product: {
id: string;
name: string;
price: number;
};
from?: string;
};
};
type Props = NativeStackScreenProps<RootStackParamList, 'ProductDetails'>;
const ProductDetailsScreen: React.FC<Props> = ({route}) => {
const {product, from} = route.params;
return (
<View>
<Text>{product.name}</Text>
<Text>Price: ${product.price}</Text>
{from && <Text>From: {from}</Text>}
</View>
);
};
更新参数 #
tsx
import React from 'react';
import {View, Button} from 'react-native';
const DetailsScreen = ({navigation, route}) => {
return (
<View>
<Text>Current count: {route.params.count || 0}</Text>
<Button
title="Increase"
onPress={() =>
navigation.setParams({
count: (route.params.count || 0) + 1,
})
}
/>
</View>
);
};
初始参数 #
tsx
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{count: 0, title: 'Default Title'}}
/>
导航事件 #
监听导航事件 #
tsx
import React from 'react';
import {Text} from 'react-native';
import {useNavigation} from '@react-navigation/native';
const MyScreen = () => {
const navigation = useNavigation();
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
console.log('Screen focused');
});
const blurUnsubscribe = navigation.addListener('blur', () => {
console.log('Screen blurred');
});
return () => {
unsubscribe();
blurUnsubscribe();
};
}, [navigation]);
return <Text>My Screen</Text>;
};
可用事件 #
| 事件 | 说明 |
|---|---|
| focus | 页面获得焦点 |
| blur | 页面失去焦点 |
| state | 导航状态变化 |
| beforeRemove | 页面即将被移除 |
阻止返回 #
tsx
import React, {useEffect} from 'react';
import {BackHandler, Alert} from 'react-native';
import {useNavigation} from '@react-navigation/native';
const FormScreen = () => {
const navigation = useNavigation();
useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', e => {
e.preventDefault();
Alert.alert(
'确认离开?',
'您有未保存的更改,确定要离开吗?',
[
{text: '取消', style: 'cancel'},
{
text: '离开',
style: 'destructive',
onPress: () => navigation.dispatch(e.data.action),
},
],
);
});
return unsubscribe;
}, [navigation]);
return <Text>Form Screen</Text>;
};
深层链接 #
配置深层链接 #
tsx
import React from 'react';
import {NavigationContainer, LinkingOptions} from '@react-navigation/native';
const linking: LinkingOptions<RootStackParamList> = {
prefixes: ['myapp://', 'https://myapp.com'],
config: {
screens: {
Home: '',
ProductDetails: {
path: 'product/:id',
parse: {
id: (id: string) => id,
},
},
Profile: 'profile/:userId',
},
},
};
const App = () => {
return (
<NavigationContainer linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="ProductDetails" component={ProductDetailsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
处理深层链接 #
tsx
import {Linking} from 'react-native';
const App = () => {
const [initialUrl, setInitialUrl] = useState<string | null>(null);
useEffect(() => {
Linking.getInitialURL().then(url => {
setInitialUrl(url);
});
const subscription = Linking.addEventListener('url', ({url}) => {
console.log('Deep link received:', url);
});
return () => subscription.remove();
}, []);
return (
<NavigationContainer linking={linking}>
{}
</NavigationContainer>
);
};
iOS 配置 #
在 ios/MyApp/Info.plist 中添加:
xml
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Android 配置 #
在 android/app/src/main/AndroidManifest.xml 中添加:
xml
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
导航状态管理 #
获取当前状态 #
tsx
import React from 'react';
import {useNavigationState} from '@react-navigation/native';
const CurrentScreen = () => {
const state = useNavigationState(state => state);
const currentRoute = state.routes[state.index];
return <Text>Current route: {currentRoute.name}</Text>;
};
导航 Ref #
tsx
import React, {useRef} from 'react';
import {NavigationContainerRef} from '@react-navigation/native';
const App = () => {
const navigationRef = useRef<NavigationContainerRef>(null);
const navigateToDetails = () => {
navigationRef.current?.navigate('Details', {id: '123'});
};
return (
<>
<NavigationContainer ref={navigationRef}>
<Stack.Navigator>
{}
</Stack.Navigator>
</NavigationContainer>
</>
);
};
状态持久化 #
tsx
import React, {useState, useEffect} from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {NavigationContainer} from '@react-navigation/native';
const PERSISTENCE_KEY = 'NAVIGATION_STATE';
const App = () => {
const [isReady, setIsReady] = useState(false);
const [initialState, setInitialState] = useState();
useEffect(() => {
const restoreState = async () => {
try {
const savedStateString = await AsyncStorage.getItem(PERSISTENCE_KEY);
const state = savedStateString ? JSON.parse(savedStateString) : undefined;
setInitialState(state);
} finally {
setIsReady(true);
}
};
restoreState();
}, []);
if (!isReady) {
return null;
}
return (
<NavigationContainer
initialState={initialState}
onStateChange={state => {
AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state));
}}>
{}
</NavigationContainer>
);
};
自定义导航器 #
自定义 Tab Bar #
tsx
import React from 'react';
import {View, TouchableOpacity, Text, StyleSheet} from 'react-native';
import {BottomTabBarProps} from '@react-navigation/bottom-tabs';
const CustomTabBar: React.FC<BottomTabBarProps> = ({state, descriptors, navigation}) => {
return (
<View style={styles.container}>
{state.routes.map((route, index) => {
const {options} = descriptors[route.key];
const label = options.tabBarLabel ?? route.name;
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}
accessibilityRole="button"
accessibilityState={isFocused ? {selected: true} : {}}
onPress={onPress}
style={styles.tab}>
<Text style={[styles.label, isFocused && styles.focusedLabel]}>
{label}
</Text>
</TouchableOpacity>
);
})}
</View>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: '#fff',
borderTopWidth: 1,
borderTopColor: '#eee',
},
tab: {
flex: 1,
alignItems: 'center',
paddingVertical: 12,
},
label: {
fontSize: 12,
color: '#999',
},
focusedLabel: {
color: '#007AFF',
fontWeight: 'bold',
},
});
使用自定义 Tab Bar #
tsx
<Tab.Navigator tabBar={props => <CustomTabBar {...props} />}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
导航动画 #
自定义过渡动画 #
tsx
import React from 'react';
import {CardStyleInterpolators} from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
可用的插值器 #
| 插值器 | 效果 |
|---|---|
| forHorizontalIOS | iOS 水平滑动 |
| forVerticalIOS | iOS 垂直滑动 |
| forModalPresentationIOS | iOS 模态展示 |
| forFadeFromBottomAndroid | Android 淡入 |
| forRevealFromBottomAndroid | Android 从底部揭示 |
模态窗口 #
配置模态窗口 #
tsx
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen
name="Modal"
component={ModalScreen}
options={{
presentation: 'modal',
headerShown: false,
}}
/>
</Stack.Navigator>
全屏模态 #
tsx
<Stack.Screen
name="FullScreenModal"
component={FullScreenModalScreen}
options={{
presentation: 'fullScreenModal',
headerShown: false,
}}
/>
导航守卫 #
认证流程 #
tsx
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const App = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
return (
<NavigationContainer>
<Stack.Navigator>
{isAuthenticated ? (
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
);
};
条件导航 #
tsx
import React from 'react';
import {View, Button} from 'react-native';
import {useNavigation} from '@react-navigation/native';
const ProtectedButton = () => {
const navigation = useNavigation();
const {isAuthenticated} = useAuth();
const handlePress = () => {
if (isAuthenticated) {
navigation.navigate('Profile');
} else {
navigation.navigate('Login', {redirect: 'Profile'});
}
};
return <Button title="View Profile" onPress={handlePress} />;
};
总结 #
React Navigation 的高级功能包括:
- 参数传递:传递复杂对象和类型安全
- 导航事件:监听页面焦点和状态变化
- 深层链接:支持 URL Scheme 和 Universal Links
- 状态管理:获取和持久化导航状态
- 自定义导航器:自定义 Tab Bar 和过渡动画
- 导航守卫:实现认证流程
掌握这些高级功能,可以构建更加复杂和灵活的导航系统。
继续学习 状态管理基础,了解 React Native 的状态管理方案。
最后更新:2026-03-28