Search code examples
reactjsreact-nativeexporeact-native-flatlist

React Native with Expo app not rendering FlatList


I have no errors showing but I am getting a blank page when my app runs. It started rendering a blank page when started putting some api code which I copied and pasted from another project where it worked exactly perfect but for some reason, it is refusing to work here This is how my code looks like. This is my App.js file

import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import Screen from './app/components/Screen'
import ProductScreen from './app/screens/ProductScreen';

export default function App() {

  return (
    <Screen>
      <ProductScreen />
    </Screen>
  )
}

Then this is the product screen.js

import React, {useState, useEffect} from 'react'
import { FlatList, StyleSheet, ActivityIndicator, Text, View } from 'react-native'
import Card from '../components/Card';

export default function ProductScreen() {
    const [products, setproducts] = useState([]);
    const [loading, setloading] = useState(true);

    const getProducts = async () => {
        try {
            const response = await fetch('https://fakestoreapi.com/products/1');
            const data = await response.json();
            setproducts(data);
        } catch (error) {
            console.log("Something went wrong in your code",error)
        } finally {
            setloading(false);
        }
    }

    useEffect(() => {
        getProducts();
    }, []);

    return (
        <View>
           {loading ? <ActivityIndicator/> : (
               <FlatList
                   data={products}
                   keyExtractor={(id) => id}
                   renderItem={({item}) => (
                       <Card 
                           title={item.title}
                           subtitle={item.description}
                           img={item.image}
                       />
                   )}
               />
           )}
        </View>
    )
}

const styles = StyleSheet.create({})

And lastly the card.js file

import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import AppText from './AppText';

export default function Card({title, subtitle, img}) {
    return (
        <View style={styles.container}>
            <Image source={img} style={styles.image} />
            <View style={styles.cardText}>
                <AppText style={{color: "black"}}>{title}</AppText>
                <AppText style={{color: "#4ecdc4"}}>{subtitle}</AppText>
            </View>
        </View>
    )
}

Where could I be going wrong?


Solution

  • Well there are several issues in your Expo Snack. First your expression of:

    {loading && <FlatList />}
    

    is wrong because you're setting it to check for loading of true when after you retrieve your data in getProducts you set it to false.

    Was able to get it to work, again, with:

    import React, { useState, useEffect } from 'react'
    import { FlatList, StyleSheet, View } from 'react-native'
    import Card from '../components/Card'
    
    export default function ProductScreen() {
      const [products, setProducts] = useState([])
      const [loading, setLoading] = useState(true)
    
      const getProducts = async () => {
        try {
          const response = await fetch('https://fakestoreapi.com/products/5')
          const data = await response.json()
          setProducts([data])
          setLoading(false)
        } catch (error) {
          console.log('Something went wrong in your code', error)
        }
      }
    
      useEffect(() => {
        getProducts()
      }, [])
    
      return (
        <View style={styles.container}>
          {!loading && products.length !== 0 && (
            <View>
              <FlatList
                data={products}
                keyExtractor={(_, id) => id.toString()}
                renderItem={({ item }) => <Card title={item.title} subtitle={item.description} img={item.image} />}
              />
            </View>
          )}
        </View>
      )
    }
    
    const styles = StyleSheet.create({
      container: {
        backgroundColor: 'lightgrey',
        flex: 1,
      },
    })
    

    Another error exists in Card for Image. Per memory when passing an image URL it should be set with a URI:

    <Image source={{ uri: img }} style={styles.image} />
    

    Another issue you'll face is in ProductScreen the View style for container should have a flex: 1 applied as indicated in the code above.