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

Error Handling and Loading States

Error Handling and Loading States

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

EXACTLY as in the React web tutorial: a custom error class that distinguishes between an expired token, a missing product, and network errors – even more relevant on mobile devices with fluctuating connection quality than on the web.

magentoFetch() with differentiated error handling

api/magentoApi.js
// ... BASE_URL, ACCESS_TOKEN, PAGE_SIZE ...

export class MagentoApiError extends Error {
  constructor(message, status) {
    super(message);
    this.name = 'MagentoApiError';
    this.status = status;
  }
}

async function magentoFetch(path) {
  let response;
  try {
    response = await fetch(`${BASE_URL}${path}`, {
      headers: { Authorization: `Bearer ${ACCESS_TOKEN}` },
    });
  } catch {
    throw new MagentoApiError('Shop unreachable. Check your internet connection.', 0);
  }

  if (response.status === 401) {
    throw new MagentoApiError('Access expired or invalid. Please renew the token.', 401);
  }
  if (response.status === 404) {
    throw new MagentoApiError('Product not found.', 404);
  }
  if (!response.ok) {
    throw new MagentoApiError(`Unexpected error: ${response.status}`, response.status);
  }

  return response.json();
}

ProductDetailScreen.js with error and loading state

screens/ProductDetailScreen.js
import { useEffect, useState } from 'react';
import { ScrollView, Text, Image, ActivityIndicator, Button, StyleSheet } from 'react-native';
import {
  fetchProductBySku,
  readCustomAttribute,
  getProductImage,
  getStockInfo,
} from '../api/magentoApi';

export default function ProductDetailScreen({ route, navigation }) {
  const { sku } = route.params;
  const [product, setProduct] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    setLoading(true);
    setError(null);
    async function load() {
      try {
        const data = await fetchProductBySku(sku);
        setProduct(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }
    load();
  }, [sku]);

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

  if (error) {
    return (
      <ScrollView contentContainerStyle={styles.centered}>
        <Text style={styles.errorText}>⚠ {error}</Text>
        <Button title="Back to product list" onPress={() => navigation.goBack()} />
      </ScrollView>
    );
  }

  const description = readCustomAttribute(product, 'description');
  const imageUrl = getProductImage(product);
  const { inStock, quantity } = getStockInfo(product);

  return (
    <ScrollView style={styles.container}>
      {imageUrl && (
        <Image source={{ uri: imageUrl }} style={styles.image} resizeMode="contain" />
      )}
      <Text style={styles.title}>{product.name}</Text>
      <Text>SKU: {product.sku}</Text>
      <Text>{product.price} €</Text>
      <Text>{inStock ? `In stock (${quantity} available)` : 'Out of stock'}</Text>
      {description && <Text style={styles.description}>{description}</Text>}
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  centered: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 16 },
  errorText: { marginBottom: 16, textAlign: 'center' },
  container: { padding: 16 },
  image: { width: '100%', height: 250, marginBottom: 16 },
  title: { fontSize: 20, fontWeight: 'bold', marginBottom: 8 },
  description: { marginTop: 16 },
});

navigation.goBack() is React Navigation's counterpart to the <Link to="/"> from the React web tutorial – it navigates back to the previous screen in the stack, EXACTLY like a native "back".

Test it on purpose: provoke an error

Tipp: Try setting a wrong EXPO_PUBLIC_MAGENTO_ACCESS_TOKEN in .env (restart the dev server afterward) to see the 401 case. Or briefly enable airplane mode on your test device to provoke the network error case – a scenario considerably more common on mobile devices than on desktop.