如何通过React Native FlatList实现页面导航?解决Hook调用错误
问题:FlatList列表项跳转页面时出现Hook调用无效错误
尝试通过FlatList列表项实现页面跳转,列表项包含图片和文本,但运行代码时提示Hook调用无效的错误,多次尝试仍无法解决。
错误信息
错误:无效的Hook调用。Hook只能在函数组件的主体内部调用。可能的原因如下:
- React和渲染器(如React DOM)版本不匹配
- 违反了Hook的使用规则
- 应用中存在多个React副本
问题原因
useNavigation是React Hook,必须在函数组件的顶层作用域或自定义Hook中调用。你将它放在了renderItem这个普通渲染函数里,违反了Hook的使用规则,导致报错。
另外,代码中还有一个隐藏问题:navigation.navigate需要传入导航栈中注册的屏幕名称,而不是组件本身,原代码中MenuData存储组件的写法是错误的。
解决方案
方案一:将renderItem移到App组件内部
在App组件顶层调用useNavigation,然后把renderItem定义在组件内部,直接访问导航对象:
import { StatusBar } from 'expo-status-bar'; import { StyleSheet, Text, View, Image, FlatList, Pressable } from 'react-native'; import { useNavigation } from '@react-navigation/native'; // 导入屏幕组件 import AracScreen from './src/screens/arac'; import ServisScreen from './src/screens/servis'; // ...其他屏幕导入 // 修改MenuData:存储屏幕名称而非组件 const MenuData = [ {id:1,title:'Araç',image:require('./src/images/car.png'),screenName: 'Arac'}, {id:2,title:'Servis',image:require('./src/images/bus.png'),screenName: 'Servis'}, {id:3,title:'Mobil',image:require('./src/images/mobile.png'),screenName: 'Mobil'}, {id:4,title:'Zimmet',image:require('./src/images/inventory2.png'),screenName:'Zimmet'}, {id:5,title:'Toplantı',image:require('./src/images/meeting.png'),screenName:'Toplanti'}, {id:6,title:'Muhaberat',image:require('./src/images/cargo.png'),screenName:'Muhaberat'}, {id:7,title:'İkram Talebi',image:require('./src/images/snacks.png'),screenName:'Ikram'}, {id:8,title:'Uydu Ofisler',image:require('./src/images/outer_office.png'),screenName:'UyduOfis'}, {id:9,title:'BizCafe',image:require('./src/images/bizcafe.png'),screenName:'BizCafe'}, {id:10,title:'TimePortal',image:require('./src/images/timeportal.png'),screenName:'TimePortal'}, {id:11,title:'İSG',image:require('./src/images/safety.png')}, {id:12,title:'Hakkımızda',image:require('./src/images/about-us.png')}, {id:13,title:'Öneri Talep',image:require('./src/images/request.png')}, {id:14,title:'İstatistikler',image:require('./src/images/statics.png')}, {id:15,title:'Duyurular',image:require('./src/images/announce.png')}, ]; export default function App() { // 在组件顶层调用useNavigation const navigation = useNavigation(); // 将renderItem定义在App组件内部 const renderItem = ({item}) => { const handlePress = () => { if (item.screenName) { // 传入屏幕名称进行跳转 navigation.navigate(item.screenName); } else { console.log("Hedef ekran belirtilmemiş."); } }; return ( <View style={styles.item}> <Pressable onPress={handlePress}> <Image source={item.image} style={styles.image}/> <Text style={styles.text}>{item.title}</Text> </Pressable> </View> ); }; return ( <View style={styles.container}> <View style={styles.header}> <Image source={require('./src/images/logo-id.png')} style={{width:242, height:73, borderWidth:0}} alt='İdari İşler Dijital Platformu'/> </View> <View style={styles.body}> <View style={styles.appmenu}> <FlatList data={MenuData} numColumns={3} renderItem={renderItem} keyExtractor={(item) => item.id.toString()} /> </View> </View> <View style={styles.footer}> <Image source={require('./src/images/app-footer.png')} style={{width:100, height:40, borderWidth:0}} alt='Doğuş Teknoloji'/> </View> <StatusBar style="auto" /> </View> ); } // 补充你的StyleSheet样式 const styles = StyleSheet.create({ container: { flex: 1, // ...你的样式 }, item: { // ...你的样式 }, // ...其他样式 });
方案二:将列表项封装为独立组件
把列表项做成独立的函数组件,通过props传递导航对象:
// 定义独立的列表项组件 const MenuItem = ({item, navigation}) => { const handlePress = () => { if (item.screenName) { navigation.navigate(item.screenName); } else { console.log("Hedef ekran belirtilmemiş."); } }; return ( <View style={styles.item}> <Pressable onPress={handlePress}> <Image source={item.image} style={styles.image}/> <Text style={styles.text}>{item.title}</Text> </Pressable> </View> ); }; // 在App组件中使用 export default function App() { const navigation = useNavigation(); const renderItem = ({item}) => <MenuItem item={item} navigation={navigation} />; return ( // ...原App组件返回内容 ); }
关键注意事项
- 确保你的
App组件被NavigationContainer包裹(通常在项目入口文件中配置),否则useNavigation无法获取导航上下文:
import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import App from './App'; import AracScreen from './src/screens/arac'; // ...导入其他屏幕 const Stack = createStackNavigator(); export default function Main() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={App} /> <Stack.Screen name="Arac" component={AracScreen} /> <Stack.Screen name="Servis" component={ServisScreen} /> // ...注册其他屏幕 </Stack.Navigator> </NavigationContainer> ); }
内容的提问来源于stack exchange,提问作者Pecado
相关产品推荐
相关产品推荐

