FlatList onPress to different screen with data

1.1k Views Asked by At

I have a list of countries in a flatlist with a search filter I made using an API. I want to make it so when I press on a country's name in the flatlist, it takes me to a screen where it prints out that specific country's name and it its number of cases. LocationDataScreen is the screen I want to print out that info. Any help is appreciated :)

This is my current code below:

const fetchData = () => {
    const apiURL = "https://coronavirus-19-api.herokuapp.com/countries";
    fetch(apiURL)
      .then((response) => response.json())
      .then((responseJson) => {
        setFilteredData(responseJson);
        setMasterData(responseJson);
      })
      .catch((error) => {
        console.error(error);
      });
  };

  const SearchFilter = (text) => {
    if (text) {
      const newData = filteredData.filter((item) => {
        const itemData = item.country;

        const textData = text.toUpperCase();
        return itemData.indexOf(textData) > -1;
      });
      setFilteredData(newData);
      setSearch(text);
    } else {
      setFilteredData(masterData);
      setSearch(text);
    }
  };

  const ItemView = ({ item }) => {
    
    return (
      <RectButton
        onPress={() => navigation.navigate("LocationDataScreen")}
        style={styles.searchcontainer}
      >
        <Text style={[styles.itemStyle, { textTransform: "capitalize" }]}>
          {item.id}
          {item.country.toUpperCase()}
        </Text>
      </RectButton>
    );
  };

  const ItemSeparatorView = () => {
    return (
      <View
        style={{
          height: 1.5,
          width: "90%",
          marginLeft: 35,
          backgroundColor: "#f3f2f8",
        }}
      />
    );
  };

  return (
    <ScrollView
      contentInsetAdjustmentBehavior="automatic"
      stickyHeaderIndices={[0]}
      style={[styles.container, { flex: 1 }]}
    >
      <SearchBarCustom
        value={search}
        placeholder="Search"
        containerStyle={{ backgroundColor: "#f3f2f8" }}
        inputContainerStyle={{
          backgroundColor: "#e3e3e9",
          height: 25,
          marginHorizontal: 5,

          marginTop: -5,
        }}
        placeholderTextColor="#96969b"
        platform="ios"
        onChangeText={(text) => SearchFilter(text)}
      />
      <FlatList
        data={filteredData}
        keyExtractor={(item, index) => index.toString()}
        ItemSeparatorComponent={ItemSeparatorView}
        renderItem={ItemView}
        style={styles.listcontainer}
      />
    </ScrollView>
  );
};
2

There are 2 best solutions below

5
On BEST ANSWER

Check out a Snack that I created for you. It has the implementation.

Your ItemView function should look like this

const ItemView = ({ item }) => {
    return (
      <RectButton
        onPress={() =>
          navigation.navigate('LocationDataScreen', { item })
        } // In this line..all the item keys are being passed as props for next screen
        style={styles.searchcontainer}>
        <Text style={[styles.itemStyle, { textTransform: 'capitalize' }]}>
          {item.id}
          {item.country.toUpperCase()}
        </Text>
      </RectButton>
    );
  };

Your LocationDataScreen.js screen should look like this

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';

function LocationDataScreen({ route, navigation }) { // You can access props from here
  const { item } = navigation.state.params || {};
  return (
    <View style={styles.container}>
      <Text>Country Name - {item.name}</Text>
      <Text>Country Cases - {item.cases}</Text>
    </View>
  );
}

export default LocationDataScreen;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
});

For Custom Header Title as item.country we can do this

In you ItemView function your onPress should look like this

onPress={() =>
          navigation.navigate('Screen2', { item: item, name: item.country })
        }

Your Stack.Screen part for second screen should look like this

  <Stack.Screen
        name="Screen2"
        component={Screen2}
        options={({ route }) => ({
          headerTitle: route.params.name,
          headerShown: true,
        })}
      />

Now when you click on the country you'll see its name on the top as Header title.

Check my Snack to see working example.

5
On

You need to pass data to the LocationDataScreen.tsx as props. Here is how you can do it.

Your onPress function should look like this:

onPress={() =>
  navigation.navigate('LocationDataScreen', { ...item })
}

And to obtain the passed data, you can write this code in you lifecycle functions(eg: componentDidMount(), etc..)

   this.props.navigation.state.params

You can also save it directly in the state of you screen LocationDataScreen.tsx. The code for LocationDataScreen.tsx will look something like this while using Class:

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';

interface Props {
  navigation: any
}

interface State {
  population: Int16Array;
  name: String
}

class LocationDataScreen extends React.Component<Props, State> {
  constructor(props:Props){
  super(props);
  this.state= {
    ...props.navigation.state.params
  }
}

  render(){
    const {population, name} = this.state;
    return (
      <View>
        <Text>Country Name - {name}</Text>
        <Text>Country Population - {population}</Text>
      </View>
    );
  }
}

export default LocationDataScreen;

While using Function

function LocationDataScreen({ route, navigation }) {
  const { country, cases } = route.params

  return (
    <View style={styles.container}>
      <Text>{country}</Text>
      <Text>{cases}</Text>
    </View>
  );
}

Also your stack navigator should look something like this

  const CountryRoute = createStackNavigator(
  {
       CountryList: {
         screen: CountryList,
       },
       
       LocationDataScreen: {
         screen: LocationDataScreen, 
       },
    
  },
  {
    initialRouteName: 'CountryList',
  },
);

For StackNavigation, I am using:

    "react-navigation-stack": "^1.10.3",

That should be it.