React Native导航异常:Invalid hook call error问题求助
React Native导航错误修复方案
错误原因分析
- Hook规则违反:在函数组件外部调用了
useNavigation钩子,不符合React Hooks只能在组件内部或自定义Hook中调用的规则。 - 导航上下文缺失:
Header组件被放在NavigationContainer外部,无法获取导航上下文,导致导航功能失效。 - 错误依赖导入:导入了Web端路由库
react-router-dom的useNavigate,React Native应用应使用@react-navigation系列库实现导航,无需该依赖。 - 组件注册失败:上述错误导致应用初始化异常,触发
AppRegistry.registerComponent未执行的错误。
修复步骤及代码修改
1. 修正app.tsx
移除外部的useNavigation调用,删除无效依赖,调整组件结构确保Header在导航上下文内:
import React, { useEffect } from 'react'; import { StyleSheet, View } from 'react-native'; import Footer from './components/footer'; import Header from './components/header'; import Home from './screens/home/home'; import Login from './screens/login/login'; import ScheduleBody from './screens/schedule/body'; import { NavigationContainer } from '@react-navigation/native'; import { StackParams } from './components/navigation'; import colors from './components/colors'; import AsyncStorage from "@react-native-async-storage/async-storage"; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import PersonalRecords from './screens/pr/personalRecords'; import UserPage from './screens/user/userPage'; import Protein from './screens/protein/protein'; const Stack = createNativeStackNavigator<StackParams>(); const App = () => { const [loggedIn, setLoggedIn] = React.useState(false); const [initialRouteName, setInitialRouteName] = React.useState('Login'); const checkLoggedIn = async () => { const user = await AsyncStorage.getItem('user'); if (user) { setLoggedIn(true); setInitialRouteName('Home'); } }; useEffect(() => { checkLoggedIn(); }, []); return ( <NavigationContainer> <View style={styles.container}> {/* Header现在处于导航上下文内部,可正常获取导航实例 */} {!loggedIn && <Header />} <Stack.Navigator initialRouteName={initialRouteName}> <Stack.Screen name='Home' component={Home} options={{ headerShown: false }}/> <Stack.Screen name="Schedule" component={ScheduleBody} options={{ headerShown: false }} /> <Stack.Screen name="PersonalRecords" component={PersonalRecords} options={{ headerShown: false }} /> <Stack.Screen name="Login" component={Login} options={{ headerShown: false }} /> <Stack.Screen name="User" component={UserPage} options={{ headerShown: false }} /> <Stack.Screen name="Protein" component={Protein} options={{ headerShown: false }} /> </Stack.Navigator> {!loggedIn && <Footer />} </View> </NavigationContainer> ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background, }, }); export default App;
2. 修正header.tsx
直接在组件内部使用useNavigation钩子,无需通过props传递导航实例:
import React, { useEffect } from 'react'; import { View, Text, StyleSheet, Image, TouchableOpacity } from 'react-native'; import colors from './colors'; import { calendar, activeWorkout, restDay, streak_25 } from '../assets/assets'; import { StackParams } from './navigation'; import { useNavigation } from '@react-navigation/native'; import { StackNavigationProp } from '@react-navigation/stack'; type HeaderNavigationProp = StackNavigationProp<StackParams, 'Schedule'>; const Header = () => { const navigation = useNavigation<HeaderNavigationProp>(); const [hasWorkout, setHasWorkout] = React.useState(false); useEffect(() => { setHasWorkout(false); }, []); const toggleActiveWorkout = () => { setHasWorkout(!hasWorkout); }; const handleCalender = () => { navigation.navigate('Schedule'); }; return ( <View> <View style={styles.centerContainer} > {hasWorkout ? ( <Image style={styles.textLeft} source={ activeWorkout } /> ) : ( <Image style={styles.textLeft} source={ restDay } /> )} <Text style={styles.textCenter}>25<Image style={styles.streak} source={streak_25}/></Text> <TouchableOpacity style={styles.textRight} activeOpacity={0.5} onPress={handleCalender}> <Image source={calendar} /> </TouchableOpacity> </View> </View> ); }; const styles = StyleSheet.create({ centerContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 20, paddingVertical: 10, backgroundColor: colors.primary, }, textLeft: { width: 40, height: 40, }, textCenter: { fontSize: 24, fontWeight: 'bold', color: colors.white, }, streak: { width: 20, height: 20, marginLeft: 5, }, textRight: { width: 40, height: 40, }, }); export default Header;
3. 清理无效依赖
删除app.tsx中import { useNavigate } from 'react-router-dom';这一行,并执行以下命令移除无用依赖:
npm uninstall react-router-dom
4. 重启Metro服务
停止当前运行的Metro服务,回到项目根目录执行命令重启:
npx react-native start --reset-cache
验证修复
完成上述修改后重新运行应用,导航功能应正常工作,所有错误信息不再出现。
内容的提问来源于stack exchange,提问作者david backx
相关产品推荐
相关产品推荐

