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

Daten lokal speichern mit AsyncStorage

Daten lokal speichern mit AsyncStorage

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

Wenn ein Nutzer die App schließt und neu öffnet, ist bisher der gesamte State weg – der Warenkorb ist leer, die Favoriten sind vergessen. Um Daten über App-Neustarts hinweg zu speichern, gibt es AsyncStorage.

Installation

npx expo install @react-native-async-storage/async-storage

Der Vergleich zu localStorage

Wenn Sie localStorage aus dem Browser kennen, ist AsyncStorage konzeptionell fast identisch – Schlüssel-Wert-Speicher für Strings. Der große Unterschied: localStorage ist SYNCHRON (localStorage.setItem(...) blockiert kurz, bis fertig), AsyncStorage ist ASYNCHRON (gibt ein Promise zurück, das Sie mit await abwarten) – das ist nötig, weil der native Speicherzugriff auf iOS/Android nicht blockierend sein darf, sonst würde die ganze App-Oberfläche kurz einfrieren.

HTML/WebReact Native
localStorage.setItem('key', 'wert')await AsyncStorage.setItem('key', 'wert')
localStorage.getItem('key')await AsyncStorage.getItem('key')
localStorage.removeItem('key')await AsyncStorage.removeItem('key')
nur Strings, komplexe Daten via JSON.stringify()identisch: nur Strings, komplexe Daten via JSON.stringify()/JSON.parse()

hooks/useCart.js anlegen: ein eigener Hook

Legen Sie einen neuen Ordner hooks/ mit der Datei useCart.js an. Das ist ein sogenannter "Custom Hook" (Funktionsname beginnt mit use) – eine wiederverwendbare Funktion, die andere Hooks wie useState/useEffect kombiniert:

hooks/useCart.js
import { useState, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';

const STORAGE_KEY = 'warenkorb';

export function useCart() {
  const [cart, setCart] = useState([]);

  // Beim Start: gespeicherten Warenkorb laden
  useEffect(() => {
    async function loadCart() {
      const saved = await AsyncStorage.getItem(STORAGE_KEY);
      if (saved) {
        setCart(JSON.parse(saved));
      }
    }
    loadCart();
  }, []);

  // Bei jeder Änderung: Warenkorb speichern
  async function addProduct(product) {
    const newCart = [...cart, product];
    setCart(newCart);
    await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(newCart));
  }

  return { cart, addProduct };
}

Jede Komponente, die useCart() aufruft, bekommt Zugriff auf denselben Muster-Code, ohne ihn zu duplizieren. [...cart, product] erzeugt ein NEUES Array mit allen alten Einträgen plus dem neuen – React-State darf niemals direkt verändert werden (z. B. cart.push(product) wäre falsch), sondern immer nur durch ein komplett neues Objekt/Array ersetzt werden. Das ist einer der häufigsten Anfängerfehler.

ProductDetailScreen.js um Warenkorb-Button erweitern

Jetzt verwenden wir useCart in unserem echten screens/ProductDetailScreen.js aus Kapitel 10. Ersetzen Sie den kompletten Inhalt der Datei durch diese Version:

screens/ProductDetailScreen.js
import { useState, useEffect } from 'react';
import {
  View,
  Text,
  Image,
  ActivityIndicator,
  TouchableOpacity,
  StyleSheet,
} from 'react-native';
import { fetchProductBySku } from '../api/magentoApi';
import { useCart } from '../hooks/useCart';

function ProductDetailScreen({ route }) {
  const { productSku } = route.params;
  const [product, setProduct] = useState(null);
  const [loading, setLoading] = useState(true);
  const { cart, addProduct } = useCart();

  useEffect(() => {
    async function loadProduct() {
      try {
        const data = await fetchProductBySku(productSku);
        setProduct(data);
      } catch (error) {
        console.error(error);
      } finally {
        setLoading(false);
      }
    }
    loadProduct();
  }, [productSku]);

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

  if (!product) {
    return <Text style={styles.error}>Produkt konnte nicht geladen werden.</Text>;
  }

  return (
    <View style={styles.container}>
      <Image source={{ uri: product.imageUrl }} style={styles.image} />
      <Text style={styles.name}>{product.name}</Text>
      <Text style={styles.price}>{product.price.toFixed(2)} €</Text>
      <TouchableOpacity style={styles.cartButton} onPress={() => addProduct(product)}>
        <Text style={styles.cartButtonText}>
          In den Warenkorb ({cart.length})
        </Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 16 },
  loader: { flex: 1, justifyContent: 'center' },
  error: { textAlign: 'center', marginTop: 24, color: '#ef4444' },
  image: { width: '100%', height: 220, borderRadius: 8, marginBottom: 16 },
  name: { fontSize: 22, fontWeight: 'bold', marginBottom: 8 },
  price: { fontSize: 18, color: '#6b7280', marginBottom: 20 },
  cartButton: {
    backgroundColor: '#111827',
    borderRadius: 8,
    paddingVertical: 14,
    alignItems: 'center',
  },
  cartButtonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
});

export default ProductDetailScreen;

Neu ist der Import von useCart, die Zeile const {{ cart, addProduct }} = useCart(); und der Button am Ende. Da useCart den Warenkorb selbst per AsyncStorage lädt und speichert, muss sich ProductDetailScreen um nichts weiter kümmern – der Warenkorb bleibt auch nach vollständigem Schließen der App erhalten.

Fertige Projektstruktur – genau die aus Kapitel 3 angekündigte

produktkatalog-app/
├── App.js                        (Einstiegspunkt: Navigation)
├── app.json                      (Expo-Konfiguration)
├── package.json                  (Pakete, wie composer.json)
├── api/
│   └── magentoApi.js             (Verbindung zur Magento-REST-API)
├── components/
│   └── ProductCard.js            (wiederverwendbare Produktkarte)
├── hooks/
│   └── useCart.js                (Warenkorb, dauerhaft gespeichert)
├── screens/
│   ├── ProductListScreen.js      (Produktliste + Suche)
│   └── ProductDetailScreen.js    (Produktdetails + Warenkorb)
└── assets/                       (Icons, Bilder)

Damit ist unser Projekt komplett: eine echte, funktionierende App mit Produktliste, Live-Suche, Detailseite, Favoriten und einem dauerhaft gespeicherten Warenkorb – genau die Struktur, die wir uns in Kapitel 3 vorgenommen hatten. Die restlichen Kapitel drehen sich jetzt um Debugging, Tests auf echten Geräten und Veröffentlichung.

Achtung: AsyncStorage ist NICHT verschlüsselt und nicht für sensible Daten wie Passwörter oder Zahlungsinformationen gedacht. Dafür gibt es expo-secure-store, das die verschlüsselten System-Schlüsselspeicher von iOS (Keychain) und Android (Keystore) nutzt.