iToverDose/Software· 1 MAI 2026 · 04:00

Saubere Architektur in React Native: So bleiben Apps wartbar und fehlerfrei

Die meisten React-Native-Projekte scheitern nicht an fehlenden Features, sondern an unkontrollierbarem Code-Wachstum. Warum saubere Architektur hier mehr ist als nur Ordnerstrukturen – und wie sie typische Fallstricke vermeidet.

DEV Community5 min0 Kommentare

Nach etwa vier Monaten in der Entwicklung eines React-Native-Projekts stößt jedes Team an dieselbe unsichtbare Wand: Plötzlich misst ein einfacher Bildschirm nicht mehr 80, sondern 400 Zeilen Code. Ein großer Teil davon besteht aus useEffect-Ketten, die API-Aufrufe koordinieren, während Push-Benachrichtigungen die App in Zustände versetzen, die niemand reproduzieren kann.

Saubere Architektur in React Native ist kein Thema von Ordnerhierarchien oder Schichten – sie entscheidet darüber, ob Ihr Team die Anwendung noch verstehen und warten kann, wenn asynchrone Abläufe, Navigation und native Module aufeinandertreffen.

Warum die Standardarchitektur scheitert

Die gängige Praxis in React Native folgt dem Prinzip „Alles landet dort, wo es zuerst gebraucht wird“. API-Aufrufe landen im Handler, der sie auslöst. Der Zustand wird im Bildschirm verwaltet, der ihn anzeigt. Native Module werden direkt aus Buttons aufgerufen. Diese Struktur funktioniert in den ersten Wochen – doch sie scheitert an folgenden Szenarien:

  • Asynchrone Abläufe überdauern ihre Aufrufer. Ein Nutzer startet eine Anfrage, wechselt dann per Benachrichtigung auf einen anderen Bildschirm. Das ursprüngliche Promise löst sich auf und versucht, einen Setter zu aktualisieren, der längst nicht mehr existiert.
  • Native Module vermischen sich mit der Oberfläche. Ein Bildschirm ruft direkt NativeModules.Audio.start() auf. Mit iOS 17 ändern sich die Audio-Session-Semantiken – plötzlich funktionieren drei Bildschirme nicht mehr, obwohl nur einer betroffen sein sollte.
  • Authentifizierungs-Rennen. Ein Token-Refresh läuft ab, während drei weitere Anfragen gleichzeitig aktiv sind. Zwei Anfragen werden wiederholt, eine meldet den Nutzer ab, eine leakt das alte Token.
  • Drift zwischen ähnlichen Logiken. Die Funktion „Nachricht senden“ existiert in zwei Bildschirmen. Einer erhält eine neue Validierungsregel – der andere nicht.

Das typische Muster dahinter:

const handleSend = async () => {
  const res = await api.post('/messages', input)
  setMessages(prev => [...prev, res.data])
}

Dieser Code ist nicht falsch – das Problem entsteht erst, wenn dieselbe Logik ein zweites Mal, minimal abgewandelt, in einem anderen Bildschirm implementiert wird.

Drei Schichten, eine klare Regel

Vergessen Sie Diagramme mit zig Schichten. Die minimale Struktur für saubere Architektur besteht aus drei klar getrennten Bereichen:

  • Präsentation: Bildschirme, Komponenten, Hooks. Verantwortlich für das Rendern und die Orchestrierung der Oberfläche.
  • Domäne: Use Cases und reine Geschäftslogik. Enthält keine Abhängigkeiten zu react, fetch oder NativeModules.
  • Daten: API-Clients, lokale Speicherung, Brücken zu nativen Modulen. Kennt die Außenwelt und deren Eigenheiten.

Die zentrale Regel lautet: Die Oberfläche kommuniziert ausschließlich mit der Domäne – niemals direkt mit der Datenebene.

Use Cases als klare Grenzen

Der Unterschied liegt im Delegieren statt im Implementieren. Statt:

const handleSend = async () => {
  const res = await api.post('/messages', input)
  setMessages(prev => [...prev, res.data])
}

wird die Logik in einen Use Case ausgelagert:

class SendMessage {
  constructor(private repo: MessageRepository) {}

  async execute(input: SendMessageInput) {
    // Validierung, Geschäftsregeln, Orchestrierung
    return this.repo.send(input)
  }
}

Der Use Case SendMessage wird zur einzigen Stelle, an der definiert ist, wie eine Nachricht tatsächlich versendet wird. Zwei Bildschirme, die denselben Use Case aufrufen, können nicht auseinanderdriften – weil es nur eine Instanz davon gibt.

Die Datenebene übernimmt die konkrete Implementierung über ein Repository-Interface:

interface MessageRepository {
  send(input: SendMessageInput): Promise<Message>
}

Der Use Case hängt von diesem Interface ab, während die Implementierung in der Datenebene liegt. Die Oberfläche importiert weder das Repository noch den Use Case direkt – stattdessen importiert sie den Use Case, ruft execute() auf und kümmert sich nicht weiter.

Warum React Native besondere Fallstricke birgt

Viele Artikel zu sauberer Architektur ignorieren einen entscheidenden Punkt: Webanwendungen haben zwei Schichten – Oberfläche und API. React Native hingegen kombiniert Oberfläche, API, Navigations-Lebenszyklus, native Module, Hintergrund-/Vordergrund-Übergänge und plattformspezifische Unterbrechungen. Jede dieser Schichten verstärkt die Kosten von Schichtvermischungen.

  • Asynchrone Abläufe überleben ihre Bildschirme. Eine Anfrage startet auf Bildschirm A und löst sich erst aus, wenn der Nutzer bereits auf Bildschirm C ist. Greift die Auflösung auf lokale Setter, Navigations-Referenzen oder Context zu, die nicht mehr existieren, entsteht ein Fehler, der nur bei schnellen Nutzerinteraktionen auftritt. Ein Use Case bietet eine zentrale Stelle, um Abbruchlogik, Idempotenz oder die Frage „Hört der Aufrufer noch zu?“ zu steuern – der Bildschirm muss davon nichts wissen.
  • Native Module gehören nicht in Handler. Der direkte Aufruf von NativeModules.Audio.start() in einem Button-Handler verknüpft die Oberfläche mit plattformspezifischem Verhalten. Plattformspezifisches Verhalten ändert sich häufig – zwischen iOS- und Android-Versionen, zwischen Simulator und echtem Gerät. Verpacken Sie das Modul stattdessen in ein Repository und exponieren Sie einen Use Case wie StartRecording. Die Oberfläche wird plattformunabhängig, während die plattformspezifische Logik einen zentralen Ort hat, an dem sie gewartet werden kann – besonders, wenn iOS plötzlich seine Semantiken ändert.
  • Authentifizierungs-Rennen und Rehydrierung. Ein klassischer Bug in React Native: Ein Token-Refresh überlappt sich mit drei laufenden Anfragen. Wenn die Auth-Logik auf einen Axios-Interceptor, einen Context-Provider und einen Bildschirm verteilt ist, wird das Rennen zum unlösbaren Problem. Es gibt keine zentrale Stelle, die serialisiert werden kann. Ein RefreshSession-Use Case, der die Warteschlange kontrolliert, macht das Problem handhabbar – wenn auch langweilig, aber machbar.

Tests werden ehrlich

Der größte praktische Vorteil sauberer Architektur liegt nicht in der Wiederverwendbarkeit, sondern darin, dass Tests plötzlich ohne Framework auskommen.

it('sends a message via the repo', async () => {
  const repo = new FakeMessageRepo()
  const useCase = new SendMessage(repo)
  await useCase.execute({ body: 'hi' })
  expect(repo.sent).toHaveLength(1)
})

Kein Render-Baum. Kein react-test-renderer. Keine gemockten NativeModules. Kein Detox. Der Use Case läuft in reinem Node und beendet sich in Millisekunden. Der Wert der Architektur zeigt sich daran, was testbar wird – nicht daran, wie „sauber“ der Code aussieht.

Häufige Fallstricke und wie man sie vermeidet

Nicht jede Architektur ist sauber, nur weil sie drei Ordner hat. Drei typische Fehler:

  • „Ich mache das nur dieses eine Mal“ ist keine Architektur. Ein direkter API-Aufruf „nur dieses eine Mal“ führt dazu, dass dieselbe Logik an drei Stellen schlecht implementiert wird. Entweder die Grenze wird strikt durchgesetzt – oder sie existiert nicht.
  • Drei Schichten für eine Zwei-Bildschirm-App sind Verschwendung. Bei einer einfachen Login- und List-Anwendung brauchen Sie keine Use-Case-Ebene. Wenden Sie diese Struktur erst an, wenn die Komplexität es rechtfertigt – meist zwischen dem dritten echten Feature und dem zweiten Entwickler im Team.
  • Ordner sind keine Grenzen. Ein domain/-Verzeichnis nützt nichts, wenn ein Bildschirm trotzdem fetch direkt aufruft. Die Ordnerstruktur dient nur der Dokumentation. ESLint-Regeln und Code-Reviews sind die eigentlichen Durchsetzer der Architektur.

Der größte Aufwand entsteht anfangs: Ein neues Feature berührt jetzt drei Dateien statt einer. Doch dieser Aufwand zahlt sich aus, sobald sich Nutzerverhalten, Plattformen oder Geschäftsregeln ändern. Saubere Architektur ist kein Ziel – sie ist die einzige Möglichkeit, in der sich ständig wandelnden Welt von React Native langfristig produktiv zu bleiben.

KI-Zusammenfassung

React Native'de temiz mimari, uygulamalarınızı daha iyi yönetmenize ve bakımını yapmanıza yardımcı olur

Kommentare

00
KOMMENTAR SCHREIBEN
ID #Q1PTQO

0 / 1200 ZEICHEN

Menschen-Check

2 + 7 = ?

Erscheint nach redaktioneller Prüfung

Moderation · Spam-Schutz aktiv

Noch keine Kommentare. Sei der erste.