How to use Flatlist for navigation?

39 views Asked by At

I'd tried to navigate screens via flatlist items but couldn't succeed. This is my code that gives an error. Flatlist has two element which is image, text so I want to make them for navigation to go other screens. I'd tried lots of things but couldn't do it. Is there any possibility to do it?

App.js

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Image, FlatList, Pressable } from 'react-native';
import { useNavigation } from '@react-navigation/native';


// Screens
import AracScreen from './src/screens/arac';
import ServisScreen from './src/screens/servis';
import MobilScreen from './src/screens/mobil';
import ZimmetScreen from './src/screens/zimmet';
import ToplantiScreen from './src/screens/toplanti';
import MuhaberatScreen from './src/screens/muhaberat';
import IkramScreen from './src/screens/ikram';
import UyduOfisScreen from './src/screens/uyduofis';
import BizCafeScreen from './src/screens/bizcafe';
import TimePortalScreen from './src/screens/timeportal';


// Menu
const MenuData = [
  {id:1,title:'Araç',image:require('./src/images/car.png'),screen: AracScreen},
  {id:2,title:'Servis',image:require('./src/images/bus.png'),screen: ServisScreen},
  {id:3,title:'Mobil',image:require('./src/images/mobile.png'),screen: MobilScreen},
  {id:4,title:'Zimmet',image:require('./src/images/inventory2.png'),screen:ZimmetScreen},
  {id:5,title:'Toplantı',image:require('./src/images/meeting.png'),screen:ToplantiScreen},
  {id:6,title:'Muhaberat',image:require('./src/images/cargo.png'),screen:MuhaberatScreen},
  {id:7,title:'İkram Talebi',image:require('./src/images/snacks.png'),screen:IkramScreen},
  {id:8,title:'Uydu Ofisler',image:require('./src/images/outer_office.png'),screen:UyduOfisScreen},  
  {id:9,title:'BizCafe',image:require('./src/images/bizcafe.png'),screen:BizCafeScreen},
  {id:10,title:'TimePortal',image:require('./src/images/timeportal.png'),screen:TimePortalScreen},
  {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')},
]

const renderItem = ({item}) => {

  const navigation = useNavigation();

  const handlePress = () => {
    if (item.screen) {
      navigation.navigate(item.screen);
    } 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>
  )
};


export default function App() {
  
  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>
  );  
}

Error

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.

Thanks in advance.

3

There are 3 answers

0
Yakupguly Malikov On

I think it is because you need to move your renderItem function inside the App function since useNavigation is not allowed to use out of React component:

export default function App() {

    const renderItem = ({item}) => {
    
      const navigation = useNavigation();
    
      const handlePress = () => {
        if (item.screen) {
          navigation.navigate(item.screen);
        } 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>
    );  
}
0
ko100v.d On

1.

export default function App() {

    const navigation = useNavigation(); // add here

    const renderItem = ({item}) => {
    
      // const navigation = useNavigation(); remove from here
    
      const handlePress = () => {
        if (item.screen) {
          navigation.navigate(item.screen);
        } else {
          console.log("Hedef ekran belirtilmemiş.");
        }
      };

2.

navigation.navigate takes 'string' as a parameter to which screen you want to navigate that is defined in your navigator. In your example you're passing item.screen which is an import, try to use the screen you have set to <Stack.Screen name='the-string-you-need-to-use' component='ScreenImport'/>

3. There is no need to have an array of imported screens.

  {id:1,title:'Araç',image:require('./src/images/car.png'),screen: AracScreen}

Remove the screen, and just do a simple switch case inside the render item to determine to which screen you want to navigate to.

1
Pecado On

Using the suggestions given, I moved towards different solutions. Finally, I reached the result I wanted by writing the code as follows.

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Image, FlatList, Pressable } from 'react-native';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';


// Ekranlar
import AracScreen from './src/screens/arac';
import ServisScreen from './src/screens/servis';
import MobilScreen from './src/screens/mobil';
import ZimmetScreen from './src/screens/zimmet';
import ToplantiScreen from './src/screens/toplanti';
import MuhaberatScreen from './src/screens/muhaberat';
import IkramScreen from './src/screens/ikram';
import UyduOfisScreen from './src/screens/uyduofis';
import BizCafeScreen from './src/screens/bizcafe';
import TimePortalScreen from './src/screens/timeportal';


// Menu
const MenuData = [
  {id:1,title:'Araç',image:require('./src/images/car.png'),screen: AracScreen},
  {id:2,title:'Servis',image:require('./src/images/bus.png'),screen: ServisScreen},
  {id:3,title:'Mobil',image:require('./src/images/mobile.png'),screen: MobilScreen},
  {id:4,title:'Zimmet',image:require('./src/images/inventory2.png'),screen:ZimmetScreen},
  {id:5,title:'Toplantı',image:require('./src/images/meeting.png'),screen:ToplantiScreen},
  {id:6,title:'Muhaberat',image:require('./src/images/cargo.png'),screen:MuhaberatScreen},
  {id:7,title:'İkram Talebi',image:require('./src/images/snacks.png'),screen:IkramScreen},
  {id:8,title:'Uydu Ofisler',image:require('./src/images/outer_office.png'),screen:UyduOfisScreen},  
  {id:9,title:'BizCafe',image:require('./src/images/bizcafe.png'),screen:BizCafeScreen},
  {id:10,title:'TimePortal',image:require('./src/images/timeportal.png'),screen:TimePortalScreen},
  {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')},
]


const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Back" component={Menu} options={{ headerShown: false }} />
        <Stack.Screen name="AracScreen" component={AracScreen} options={{ headerTitle: 'Araç' }} />
        <Stack.Screen name="ServisScreen" component={ServisScreen} options={{ headerTitle: 'Servis' }} />
        <Stack.Screen name="MobilScreen" component={MobilScreen} options={{ headerTitle: 'Mobil' }} />
        <Stack.Screen name="ZimmetScreen" component={ZimmetScreen} options={{ headerTitle: 'Zimmet' }} />
        <Stack.Screen name="ToplantiScreen" component={ToplantiScreen} options={{ headerTitle: 'Toplantı' }} />
        <Stack.Screen name="MuhaberatScreen" component={MuhaberatScreen} options={{ headerTitle: 'Muhaberat' }} />
        <Stack.Screen name="IkramScreen" component={IkramScreen} options={{ headerTitle: 'İkram' }} />
        <Stack.Screen name="UyduOfisScreen" component={UyduOfisScreen} options={{ headerTitle: 'Uydu Ofis' }} />
        <Stack.Screen name="BizCafeScreen" component={BizCafeScreen} options={{ headerTitle: 'BizCafe' }} />
        <Stack.Screen name="TimePortalScreen" component={TimePortalScreen} options={{ headerTitle: 'TimePortal' }} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

function Menu() {
  const navigation = useNavigation();

  const renderItem = ({ item }) => {
    const handlePress = () => {
      if (item.screen) {
        navigation.navigate(item.screen);
      } else {
        console.log("There is no screen");
      }
    };

    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='Dijital Platform' />
      </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: 120, height: 48, borderWidth: 0 }} alt='Doğuş Teknoloji' />
      </View>

      <StatusBar style="auto" />
    </View>
  );
}

Thank you guys.