reactjsreact-nativerxjsreact-native-flatlistflatlist

Issue rendering a FlatList in React Native


I'm teaching myself React and I'm trying to use a FlatList. For some reason my list is not rendering as expected. I have some list "ListItem" objects, and when I simply render them in a View, they work fine:

Here is the ListItem:

import { View, Text, Image, StyleSheet } from "react-native";

interface Props {
  title: string;
  subtitle: string;
}

function ListItem({ title, subtitle }: Props) {
  return (
    <View style={styles.itemStyle}>
      <Image
        style={styles.imageStyle}
        source={require("../assets/user.png")}
      ></Image>
      <View>
        <Text style={styles.titleStyle}>{title}</Text>
        <Text style={styles.subtitleStyle}>{subtitle}</Text>
      </View>
    </View>
  );
}

export default ListItem;

const styles = StyleSheet.create({
  itemStyle: {
    flexDirection: "row",
    backgroundColor: "lightblue",
    width: "80%",
    height: "10%",
    borderRadius: 10,
    margin: 5,
    alignItems: "center", // aling vertically
    paddingLeft: 10,
  },
  imageStyle: {
    width: 55,
    height: 55,
  },
  titleStyle: {
    fontSize: 20,
    fontFamily: "Avenir",
    fontWeight: "600",
    paddingLeft: 10,
  },
  subtitleStyle: {
    fontSize: 15,
    fontFamily: "Avenir",
    fontWeight: "400",
    paddingLeft: 10,
    color: "grey",
  },
});

And here is the View in which I render them (not using a FlatList yet):

import {
  SafeAreaView,
} from "react-native";
import Constants from "expo-constants";
import ListItem from "./ListItem";

function FlatListScreen() {
  return (
    <SafeAreaView
      style={{
        flex: 1,
        alignItems: "center",
        backgroundColor: "#E2F0FB",
        paddingTop: Constants.statusBarHeight,
      }}
    >
      <ListItem title="William I" subtitle="Changed England forever"></ListItem>
      <ListItem
        title="Henry VIII"
        subtitle="Weird dude with lots of wives"
      ></ListItem>
      <ListItem title="Richard I" subtitle="Known as the Lionheart"></ListItem>
    </SafeAreaView>
  );
}

The result is as I expect:

enter image description here

But as soon as I try to show this in a FlatList, it gets all buggy and distorted. Here is the code:

import { SafeAreaView, FlatList, View } from "react-native";
import Constants from "expo-constants";
import ListItem from "./ListItem";

function FlatListScreen() {
  // Prepare array data for FlatList

  const items = [
    {
      id: 1,
      title: "William I",
      subtitle: "Changed England forever",
    },
    {
      id: 2,
      title: "Henry VIII",
      subtitle: "Weird dude with lots of wives",
    },
    {
      id: 3,
      title: "Richard I",
      subtitle: "Known as the Lionheart",
    },
  ];

  return (
    <SafeAreaView
      style={{
        flex: 1,
        alignItems: "center",
        backgroundColor: "#E2F0FB",
        paddingTop: Constants.statusBarHeight,
      }}
    >
      <FlatList
        data={items}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => (
          <ListItem title={item.title} subtitle={item.subtitle}></ListItem>
        )}
      ></FlatList>
    </SafeAreaView>
  );
}

export default FlatListScreen;

But this is how it shows when using the FlatList:

enter image description here

It is very basic code so I don't understand why the items are getting all squished and distorted. Please help.


Solution

  • I looked through your code I noticed where the bug might possibly be lurking. It looks like the height style property is the culprit here. The height: 20% is setting the height of your ListItem component to 20% of the FlatList height and that is why your ListItems look compressed. Also, I have taken out the width: 80% too so that it can take a 100% width of the FlatList component. I have made a change to your code and did some little refactoring as well:

    import { View, Text, Image, StyleSheet } from "react-native";
    
    function ListItem({ title, subtitle }: Props) {
      return (
        <View style={styles.itemStyle}>
          <Image
            style={styles.imageStyle}
            source={require("../assets/user.png")}
          />
          <View>
            <Text style={styles.titleStyle}>{title}</Text>
            <Text style={styles.subtitleStyle}>{subtitle}</Text>
          </View>
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      itemStyle: {
        flexDirection: "row",
        backgroundColor: "lightblue",
        borderRadius: 10,
        margin: 5,
        alignItems: "center", // aling vertically
        paddingLeft: 10,
      },
      imageStyle: {
        width: 55,
        height: 55,
      },
      titleStyle: {
        fontSize: 20,
        fontFamily: "Avenir",
        fontWeight: "600",
        paddingLeft: 10,
      },
      subtitleStyle: {
        fontSize: 15,
        fontFamily: "Avenir",
        fontWeight: "400",
        paddingLeft: 10,
        color: "grey",
      },
    });
    
    
    import { FlatList } from "react-native";
    
    function FlatListScreen() {
      // Prepare array data for FlatList
    
      const renderItem = ({ item }: { item: Props }) => {
        return <ListItem title={item.title} subtitle={item.subtitle} />;
      };
    
      return (
        <FlatList
          data={items}
          keyExtractor={(item) => item.id.toString()}
          renderItem={renderItem}
        />
      );
    }
    
    export default FlatListScreen;