Blog

Generisches ListItem in React Native mit TypeScript

Bart den Hollander

Bart den Hollander

Aktualisiert Oktober 17, 2025
4 Minuten

Bei der Verwendung von React Native werden Listen mit der FlatList-Komponente erstellt. Eine FlatList wird aus einem oder mehreren wiederholbaren Listenelementen erstellt, ein Element pro Zeile. In diesem Blog zeige ich Ihnen, wie TypeScript bei der Erstellung von FlatLists mit generischen Listenelementen helfen kann.

Dies ist eine Technik, mit der wir Boilerplate reduzieren können, aber dennoch lesbare und anpassbare FlatLists haben.

Lassen Sie uns gleich in die Grundlagen einer FlatList eintauchen, indem wir eine Liste mit StarWars-Charakteren erstellen.

const starWarsData: StarWars[] = [
  {id: '1', character: 'Luke Skywalker', hairColor: 'Blond'},
  {id: '2', character: 'Leia Organa', hairColor: 'Brown'}
];
const StarWarsListItem = ({item}: {item: StarWars}) => (
    <TouchableOpacity style={styles.item} onPress={() => onPressListItem(item)}>
      <View style={styles.textContainer}>
        <Text>Character: {item.character}</Text>
        <Text>Hair color: {item.hairColor}</Text>
      </View>
    </TouchableOpacity>
  );
return (
    <View style={styles.container}>
      <View style={styles.headerContainer}>
        <Text style={styles.headerLabel}>Star Wars Characters</Text>
      </View>
      <FlatList
        data={starWarsData}
        keyExtractor={(item) => item.id}
        renderItem={StarWarsListItem}
      />
    </View>
);

Dieser Code generiert eine Liste von Charakteren aus StarWars, wie hier gezeigt.

GenericList

Wenn wir mehrere gleich aussehende FlatLists erstellen, wollen wir nicht jedes Mal den gleichen Code schreiben. Im obigen Beispiel sehen wir, dass die lila Überschrift in jeder erstellt wird. Außerdem wird ein erstellt, um jedes Element anklickbar zu machen, was überflüssig ist. Indem wir eine Abstraktion mit einer generischen erstellen, entfernen wir diese redundanten Teile und schaffen eine effizientere Komponente. Beginnen wir mit dem generischen Teil, indem wir die Abstraktion FlatList erstellen.

type Props<ItemT> = {
  data?: ItemT[];
  onPressListItem: (item: ItemT) => void;
  renderDetails: React.FC<{item: ItemT}>;
  keyExtractor: (item: ItemT) => string;
  headerTitle: string;
};
const GenericList = <ItemT,>({
  data,
  onPressListItem,
  keyExtractor,
  headerTitle,
  renderDetails: RenderDetailsComponent
}: Props<ItemT>) => {
  const renderItem = ({item}: {item: ItemT}) => (
    <TouchableOpacity style={styles.item} onPress={() => onPressListItem(item)}>
      <View style={styles.textContainer}>
        <RenderDetailsComponent item={item} />
      </View>
    </TouchableOpacity>
  );
  return (
    <FlatList
      data={data}
      keyExtractor={keyExtractor}
      renderItem={renderItem}
      ListHeaderComponent={
        <View style={styles.container}>
          <View style={styles.headerContainer}>
            <Text style={styles.headerLabel}>{headerTitle}</Text>
          </View>
        </View>
      }
      ItemSeparatorComponent={() => <View style={styles.listSeparator} />}
    />
  );
};

Die Komponente GenericList erhält Requisiten, die im Typ Props deklariert sind. Wenn wir uns den Typ renderDetails ansehen, sehen wir die folgende Deklaration: React.FC<{item: ItemT}>.

Diese Deklaration teilt TypeScript mit, dass es nur funktionale Komponenten akzeptieren soll, die die Prop item mit dem generischen Typ ItemT haben. Dieser generische Typ sollte der gleiche Typ sein wie der Typ, der als Array mit der Requisite übergeben wird. Dies sind die Daten, die für das Rendern der Liste der Zeilen verwendet werden.

Außerdem wird die <ItemT,> Kommasyntax benötigt, weil wir eine funktionale Komponente mit einer Pfeilfunktion verwenden. Andernfalls zeigt TypeScript den folgenden Fehler an:

Parsing error: JSX element ‘ItemT’ has no corresponding closing tag

 

Verschiedene Datensätze verwenden

Der folgende Code zeigt, wie Sie die StarWars FlatList erstellen, indem Sie die gerade gezeigte Komponente GenericList verwenden.

const starWarsData: StarWars[] = [
  {id: '1', character: 'Luke Skywalker', hairColor: 'Blond'},
  {id: '2', character: 'Leia Organa', hairColor: 'Brown'}
];
const StarWarsListItem = ({item}: {item: StarWars}) => (
  <>
    <Text>Character: {item.character}</Text>
    <Text>Hair color: {item.hairColor}</Text>
  </>
);
<GenericList
  data={starWarsData}
  headerTitle="StarWars characters"
  renderDetails={StarWarsListItem}
  onPressListItem={(item: StarWars) => console.log(item)}
  keyExtractor={(item) => item.id}
/>

Der Vorteil dieser Technik ist die hohe Flexibilität bei der Darstellung von Zeilen in einer FlatList, während der replizierte Code durch die Komponente GenericList verborgen wird. Letztendlich wird dies die Testbarkeit, die Wartung und die Erfahrung der Entwickler verbessern.

Wir können die GenericList auch mit anderen Daten verwenden, wie im folgenden Codebeispiel gezeigt.

const onPressListItem = (item: Fruit | StarWars) => console.log(item);
const StarWarsListItem = ({item}: {item: StarWars}) => (
  <>
    <Text>Character: {item.character}</Text>
    <Text>Hair color: {item.hairColor}</Text>
  </>
);
const FruitListItem = ({item}: {item: Fruit}) => <Text>{item.title}</Text>;
return (
  <>
    <GenericList
      data={starWarsData}
      headerTitle="StarWars characters"
      renderDetails={StarWarsListItem}
      onPressListItem={(item: StarWars) => console.log(item)}
      keyExtractor={(item) => item.id}
    />
    <GenericList
      data={fruitData}
      headerTitle="Fruits"
      renderDetails={FruitListItem}
      onPressListItem={onPressListItem}
      keyExtractor={(item) => item.id}
    />
  </>
);

Auf diese Weise werden zwei Listen erstellt, die einen unterschiedlichen Datentyp verwenden und dennoch flexibel sind, was die Darstellung der Daten in den einzelnen Zeilen betrifft Die folgende (eingebettete) CodeSandbox zeigt die Komponente GenericList mit react-native-web. Wenn Sie auf ein ListItem klicken, erhalten Sie ein Protokoll in der Konsole. Danke, dass Sie meinen Blog lesen!

Verfasst von

Bart den Hollander

Contact

Let’s discuss how we can support your journey.