You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过React Native FlatList实现页面导航?解决Hook调用错误

问题:FlatList列表项跳转页面时出现Hook调用无效错误

尝试通过FlatList列表项实现页面跳转,列表项包含图片和文本,但运行代码时提示Hook调用无效的错误,多次尝试仍无法解决。

错误信息

错误:无效的Hook调用。Hook只能在函数组件的主体内部调用。可能的原因如下:

  1. React和渲染器(如React DOM)版本不匹配
  2. 违反了Hook的使用规则
  3. 应用中存在多个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:34:56