Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Daten von einer API laden mit fetch und useEffect

Daten von einer API laden

~11 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Bisher haben wir Produktdaten fest im Code eingetragen. Echte Apps laden Daten von einem Server – genau wie unser Magento-Shop das über die REST- oder GraphQL-API tut. Dieses Kapitel zeigt, wie.

fetch() kennen Sie bereits

Die gute Nachricht zuerst: React Native verwendet dieselbe fetch()-Funktion, die Sie aus dem Browser-JavaScript kennen. Es gibt hier keinen Unterschied zum Web:

fetch('https://meinshop.example.com/rest/de/V1/products?searchCriteria[pageSize]=10')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

Das Problem: WANN soll geladen werden?

Einfach fetch() mitten in der Komponentenfunktion aufrufen würde bei jedem Neuzeichnen ("Re-Render", z. B. durch useState-Änderungen) einen neuen Netzwerk-Aufruf auslösen – eine Endlosschleife. Dafür gibt es useEffect: einen "Nebeneffekt", der nur zu bestimmten Zeitpunkten läuft.

Eine eigene Datei für die Produkt-API-Anbindung

Achtung: Wichtig, bevor Sie weitermachen: Der Code unten braucht eine ECHTE, erreichbare API im Hintergrund – https://mironsoft.test ist die lokale Docker-Adresse DIESES Projekts und funktioniert bei Ihnen nicht. Haben Sie einen eigenen Magento-2-Shop mit aktivierter REST-API? Dann tragen Sie unten dessen Adresse ein. Haben Sie (noch) keinen? Dann überspringen Sie den Magento-Block und nutzen direkt die kostenlose Alternative weiter unten – der Rest des Tutorials (App.js, ProductListScreen.js usw.) bleibt in beiden Fällen komplett identisch, da nur diese eine Datei die Datenquelle kennt.

Statt fetch() überall im Code zu verstreuen, bündeln wir jede API-Anfrage an einer zentralen Stelle. Legen Sie einen neuen Ordner api/ mit der Datei magentoApi.js an.

Variante A: eigener Magento-Shop

Ersetzen Sie https://mironsoft.test durch die Basis-URL Ihres eigenen Shops:

api/magentoApi.js
const BASE_URL = 'https://mironsoft.test/rest/de/V1'; // ← Ihre eigene Shop-URL hier eintragen

function mapMagentoProduct(item) {
  const imageAttribute = item.custom_attributes?.find(
    (attribute) => attribute.attribute_code === 'image'
  );

  return {
    sku: item.sku,
    name: item.name,
    price: item.price,
    imageUrl: imageAttribute
      ? `https://mironsoft.test/media/catalog/product${imageAttribute.value}`
      : 'https://picsum.photos/200',
  };
}

export async function fetchProducts() {
  const response = await fetch(`${BASE_URL}/products?searchCriteria[pageSize]=20`);

  if (!response.ok) {
    throw new Error(`Magento API error: ${response.status}`);
  }

  const data = await response.json();
  return data.items.map(mapMagentoProduct);
}

Variante B: kein eigener Shop? Kostenlose Test-API ohne Anmeldung

dummyjson.com ist eine kostenlose, öffentliche Test-API mit Beispiel-Produkten – kein Account, kein API-Key nötig. Legen Sie dieselbe Datei stattdessen so an (die exportierten Funktionsnamen bleiben absichtlich identisch zu Variante A):

api/magentoApi.js
const BASE_URL = 'https://dummyjson.com';

function mapMagentoProduct(item) {
  return {
    sku: String(item.id),
    name: item.title,
    price: item.price,
    imageUrl: item.thumbnail,
  };
}

export async function fetchProducts() {
  const response = await fetch(`${BASE_URL}/products?limit=20`);

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  const data = await response.json();
  return data.products.map(mapMagentoProduct);
}

Beide Varianten exportieren exakt dieselbe Funktion fetchProducts() mit demselben Rückgabeformat (sku, name, price, imageUrl). Das ist der ganze Sinn dieser eigenen Datei: Der Rest der App (App.js und später screens/) ruft nur fetchProducts() auf und weiß gar nicht, woher die Daten wirklich kommen. Ab jetzt zeigen Kapitel-Beispiele nur noch Variante A (Magento) – wenn Sie Variante B nutzen, übertragen Sie die kommenden Erweiterungen an api/magentoApi.js einfach sinngemäß.

Magentos REST-API liefert jedes Produkt als großes, verschachteltes Objekt mit vielen Feldern, die wir gar nicht brauchen (SKU, Attribute-Sets, Website-IDs, ...). mapMagentoProduct() filtert genau die vier Felder heraus, die unsere ProductCard erwartet – das Bild steckt als eines von vielen "custom attributes" im Produkt und muss erst gesucht werden. fetchProducts() ist async ("asynchron") – das bedeutet, die Funktion gibt sofort ein Promise zurück und der eigentliche Wert kommt erst später, wenn die Netzwerk-Antwort da ist. Genau dafür ist await da: es "pausiert" die Funktion, bis das Promise erfüllt ist, ohne den Rest der App zu blockieren.

App.js aktualisieren: Produkte beim Start laden

Jetzt ersetzen wir App.js erneut komplett – diesmal lädt sie echte Daten aus Ihrem Shop, statt eine feste ProductCard anzuzeigen. Der ProductCard-Import kommt im nächsten Kapitel zurück, sobald wir eine ganze Liste anzeigen:

App.js
import { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import { fetchProducts } from './api/magentoApi';

export default function App() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function loadProducts() {
      try {
        const items = await fetchProducts();
        setProducts(items);
      } catch (error) {
        console.error(error);
      } finally {
        setLoading(false);
      }
    }
    loadProducts();
  }, []); // leeres Array = nur EINMAL beim ersten Zeichnen ausführen

  if (loading) {
    return <ActivityIndicator size="large" style={styles.loader} />;
  }

  return (
    <View style={styles.container}>
      <Text>{products.length} Produkte geladen</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  loader: { flex: 1, justifyContent: 'center' },
});

Projektstruktur nach diesem Kapitel

produktkatalog-app/
├── App.js                     (aktualisiert: lädt Produkte per useEffect)
├── app.json
├── package.json
├── api/
│   └── magentoApi.js          ← NEU
├── components/
│   └── ProductCard.js
└── assets/

Das leere Array [] als zweites Argument von useEffect ist entscheidend – es sagt React: "Führe diesen Code nur einmal aus, direkt nachdem die Komponente zum ersten Mal angezeigt wurde", vergleichbar mit dem DOMContentLoaded-Event im Web oder $(document).ready() in älterem jQuery-Code. Starten Sie die App neu (bzw. laden Sie im Entwicklermenü neu) – Sie sollten kurz den Ladeindikator und danach die Anzahl der geladenen Produkte aus Ihrem Shop sehen.

HTML/WebReact Native
window.addEventListener('DOMContentLoaded', laden)useEffect(() => { laden(); }, [])
Ladeindikator per CSS-Klasse ein-/ausblendenloading-State + bedingtes Rendern (if (loading) return ...)
fetch()identisch – fetch() ist in React Native eingebaut, kein Import nötig

Tipp: Für einen öffentlichen Endpunkt wie /rest/V1/products ohne Login benötigen Sie kein Access-Token – für geschützte Aktionen wie Bestellungen wäre ein Integration-Token nötig, das über System > Integrationen im Magento-Backend erstellt wird.