31 Routing mit React Router

Das Konzept des Routings ist fundamental für moderne Webanwendungen. Während traditionelle Websites bei jedem Navigationsvorgang eine neue HTML-Seite vom Server laden, funktionieren Single Page Applications (SPAs) nach einem anderen Prinzip: Die gesamte Anwendung wird einmal geladen, und die Navigation erfolgt durch das dynamische Austauschen von Komponenten basierend auf der aktuellen URL.

React selbst bringt keine Routing-Funktionalität mit. Stattdessen verlassen sich React-Entwickler auf spezialisierte Bibliotheken, wobei React Router die mit Abstand populärste und ausgereifteste Lösung darstellt. Diese Bibliothek wurde speziell für React entwickelt und integriert sich nahtlos in das Komponenten-Paradigma der Bibliothek.

31.1 Das Problem ohne Routing

Ohne ein Routing-System müssten React-Anwendungen die Anzeige verschiedener Inhalte über den lokalen State verwalten. Dies würde zu komplexen Zustandsstrukturen führen, bei denen eine zentrale Variable bestimmt, welche Komponente gerendert wird. Ein solcher Ansatz bringt mehrere Probleme mit sich: URLs bleiben statisch und spiegeln nicht den aktuellen Anwendungszustand wider, Benutzer können keine direkten Links zu bestimmten Ansichten teilen, die Browser-Navigation funktioniert nicht erwartungsgemäß, und Suchmaschinen können die verschiedenen Bereiche der Anwendung nicht indexieren.

React Router löst diese Probleme, indem es eine deklarative API bereitstellt, die es ermöglicht, React-Komponenten direkt mit URL-Pfaden zu verbinden. Die Bibliothek übernimmt dabei die komplexe Aufgabe der Browser-History-Verwaltung und stellt sicher, dass Vor- und Zurück-Buttons wie erwartet funktionieren.

31.2 Grundlegende Architektur

React Router basiert auf einem Provider-Pattern, das aus dem React-Ökosystem bekannt ist. Der BrowserRouter fungiert als oberster Container und stellt allen untergeordneten Komponenten den Routing-Kontext zur Verfügung. Dieser Kontext enthält Informationen über die aktuelle URL, den Browser-Verlauf und Methoden zur Navigation.

Die eigentliche Route-Definition erfolgt durch Routes und Route-Komponenten. Routes dient als Container für alle Route-Definitionen und implementiert die Logik zur Auswahl der passenden Route. Jede Route-Komponente definiert eine Verbindung zwischen einem URL-Pfad und einer React-Komponente. Diese deklarative Herangehensweise macht die Struktur der Anwendung leicht verständlich und wartbar.

31.3 Installation und Grundkonfiguration

React Router wird als separate NPM-Bibliothek installiert. Der Paketname react-router-dom deutet darauf hin, dass es sich um die DOM-spezifische Version handelt - es gibt auch Varianten für React Native und andere Umgebungen. Bei Verwendung von TypeScript sind die entsprechenden Typen meist automatisch enthalten, können aber separat installiert werden, falls sie fehlen.

npm install react-router-dom

Die Integration in eine bestehende React-Anwendung erfolgt typischerweise auf der obersten Ebene, meist in der App-Komponente. Der BrowserRouter umschließt die gesamte Anwendung und sollte nur einmal verwendet werden. Eine häufige Fehlerquelle ist die Verwendung mehrerer Router innerhalb einer Anwendung, was zu unvorhersagbarem Verhalten führen kann.

31.4 Kernkomponenten im Detail

31.4.1 BrowserRouter

Der BrowserRouter ist die moderne Implementierung für webbasierte Anwendungen. Er nutzt die HTML5 History API, um URLs zu verwalten, ohne dass Hash-Zeichen erforderlich sind. Dies führt zu sauberen URLs wie /about anstelle von /#/about. Die Komponente überwacht Änderungen der Browser-URL und informiert alle untergeordneten Router-Komponenten über Navigationsevents.

Ein wichtiger Aspekt ist, dass der BrowserRouter die gesamte Anwendung umschließen sollte. Komponenten außerhalb seines Geltungsbereichs haben keinen Zugriff auf Router-Funktionalität. Dies erklärt, warum der Router typischerweise in der obersten Komponente der Anwendung platziert wird.

31.4.2 Routes und Route

Das Routes-Element ersetzt das ältere Switch-Element aus früheren React Router-Versionen. Es implementiert eine intelligente Matching-Algorithmus, der die beste passende Route basierend auf dem aktuellen URL-Pfad auswählt. Die Reihenfolge der Route-Definitionen ist dabei weniger kritisch als in älteren Versionen, da React Router automatisch spezifischere Routen bevorzugt.

Jede Route-Komponente definiert eine Zuordnung zwischen einem Pfad und einem React-Element. Das path-Attribut spezifiziert den URL-Pfad, während das element-Attribut die zu rendernde Komponente definiert. Die Verwendung des element-Attributs anstelle von component ist ein moderneres Pattern, das eine flexiblere Übergabe von Props ermöglicht.

Link-Komponenten sind das Herzstück der SPA-Navigation. Sie rendern als HTML-Anker-Tags, aber ihr Verhalten unterscheidet sich fundamental von normalen Links. Beim Klicken auf einen Link wird kein HTTP-Request an den Server gesendet. Stattdessen wird die Browser-URL programmatisch geändert und React Router reagiert auf diese Änderung, indem es die entsprechende Komponente rendert.

Die to-Eigenschaft des Link akzeptiert sowohl absolute als auch relative Pfade. Absolute Pfade beginnen mit einem Schrägstrich und navigieren zur exakten URL, während relative Pfade relativ zur aktuellen Position interpretiert werden. Diese Flexibilität ermöglicht es, wiederverwendbare Komponenten zu erstellen, die unabhängig von ihrer Position in der URL-Hierarchie funktionieren.

31.5 Troubleshooting

Ein verbreiteter Fehler ist die Verwendung normaler <a>-Tags anstelle von Link-Komponenten für die interne Navigation. Dies führt zu vollständigen Seitenreloads und untergräbt die Vorteile einer SPA. Moderne Entwicklungstools warnen oft vor diesem Problem, aber es ist wichtig, die Unterschiede zu verstehen.

Ein weiterer häufiger Fehler besteht darin, den Router nicht korrekt zu positionieren. Komponenten, die Router-Funktionalität nutzen möchten, müssen sich innerhalb des Router-Kontexts befinden. Fehlermeldungen wie “useNavigate() may be used only in the context of a component” weisen auf dieses Problem hin.

Die Handhabung von unbekannten Routen wird oft übersehen. Ohne eine entsprechende Fallback-Route zeigt die Anwendung bei ungültigen URLs einfach eine leere Seite an. Dies führt zu einer schlechten Benutzererfahrung und sollte durch geeignete Fehlerbehandlung vermieden werden.

31.6 Performance-Überlegungen

React Router ist für Performance optimiert und führt nur dann zu Re-Renders, wenn sich die relevanten Route-Parameter ändern. Die Bibliothek nutzt React-eigene Optimierungen wie Memoization, um unnötige Berechnungen zu vermeiden.

Bei größeren Anwendungen kann es sinnvoll sein, Komponenten erst bei Bedarf zu laden. React Router unterstützt diese Technik durch die Integration mit React.lazy und Suspense. Diese Optimierung wird relevant, wenn Anwendungen viele Routen haben oder einzelne Route-Komponenten besonders groß sind.

Die Wahl der Router-Implementierung hat ebenfalls Performance-Auswirkungen. Der BrowserRouter ist für die meisten Anwendungen die beste Wahl, da er die nativen Browser-Funktionen optimal nutzt. Alternative Implementierungen wie der HashRouter sollten nur in speziellen Umgebungen verwendet werden, wo die HTML5 History API nicht verfügbar ist.

31.7 Browser-Kompatibilität und Fallbacks

Moderne Browser unterstützen die HTML5 History API vollständig, die React Router für saubere URLs verwendet. In sehr alten Browsern kann es jedoch zu Problemen kommen. Für solche Szenarien bietet React Router alternative Router-Implementierungen, die mit Hash-basierten URLs arbeiten.

Die Serverseite muss ebenfalls konfiguriert werden, um SPAs korrekt zu unterstützen. Da alle Routen clientseitig verwaltet werden, sollte der Server für alle Pfade die Haupt-HTML-Datei ausliefern. Ohne diese Konfiguration führen direkte URL-Aufrufe zu 404-Fehlern.

31.8 Debugging und Entwicklungstools

React Router integriert sich gut in die React Developer Tools und ermöglicht es, den aktuellen Router-State zu inspizieren. Bei Problemen ist es hilfreich, die aktuelle URL, die aktiven Routen und den Browser-Verlauf zu überprüfen.

Console-Logs können bei der Entwicklung hilfreich sein, sollten aber in Produktionsumgebungen entfernt werden. React Router bietet auch Debug-Modi, die zusätzliche Informationen über Route-Matching und Navigation ausgeben.