Routing-Bibliothek für Single Page Applications

TanStack Router: Navigation in einer React-Applikation

TanStack Router: Navigation in einer React-Applikation

Routing-Bibliothek für Single Page Applications

TanStack Router: Navigation in einer React-Applikation


Für React war die Standardbibliothek, wenn es um Routing geht, lange Zeit React Router. Doch in den letzten Jahren hat sich eine Alternative durchgesetzt: der TanStack Router. In diesem Artikel werfen wir sowohl einen Blick auf den TanStack Router als auch auf generelle Features einer Routing-Bibliothek für eine SPA und zeigen, wie sie die Features in Ihrer Applikation nutzen können.

Moderne Single Page Applications (SPA) bestehen aus einer Baumstruktur von Komponenten, durch die Informationen fließen. Je umfangreicher eine Applikation ist, desto größer wird auch der Komponentenbaum. Eine App besteht jedoch nicht aus nur einer Ansicht, sondern meist aus mehreren, die unabhängig voneinander sind. Das bedeutet, dass Sie je nach aktueller Ansicht einen bestimmten Teilbaum Ihrer App anzeigen und andere Teilbäume dafür ausblenden. Diese Aufgabe tritt so häufig auf, dass es Bibliotheken gibt, die sich genau um diesen Aspekt kümmern.

Es gibt zwei große Router-Ansätze für React, mit denen sich ein Neuling wie der TanStack Router messen muss. Das ist auf der einen Seite der modernisierte React Router und auf der anderen Seite die immer relevanter werdenden hybriden Ansätze, wie beispielsweise Next.js mit seinem dateisystembasierten Routing. Der TanStack Router bietet sowohl code- als auch dateisystembasiertes Routing. Beim codebasierten Ansatz, der aus dem React Router bekannt ist, arbeitet der TanStack Router mit einer Reihe von Funktionen, mit denen die Konfiguration für das Routing der Applikation umgesetzt werden kann. Im weitesten Sinn sind die Routen Objekte, mit denen Sie angeben können, welche Komponenten für welchen Pfad gerendert werden sollen. Die Einbindung in eine Applikation erfolgt über einen Provider, der sicherstellt, dass aus allen untergeordneten Komponenten auf die Router-Funktionalität zugegriffen werden kann. Die meisten Features, die Sie aus dem React Router oder vom App Router von Next.js kennen, finden Sie auf ähnliche Art auch im TanStack Router. So können Sie Variablen im Pfad definieren, verschachtelte Routen umsetzen oder Loader implementieren.

Erste Schritte mit dem TanStack Router

Sie können den TanStack Router sowohl in einer JavaScript- als auch in einer TypeScript-Applikation nutzen. Der Router selbst ist vollständig in TypeScript implementiert und spielt seine volle Stärke auch erst in einer solchen Umgebung aus. Also gehen wir im weiteren Verlauf dieses Artikels von einer TypeScript-Applikation als Grundlage aus. Mit dem Kommando npm install @tanstack/react-router installieren Sie die Bibliothek in Ihrer Applikation. Der TanStack Router stammt, wie auch TanStack Query, von Tanner Linsley. Momentan liegt der Fokus des TanStack Routers noch rein auf React. Das kann sich jedoch in Zukunft ändern, wie es auch schon bei TanStack Query der Fall war, das ursprünglich den Namen React Query trug.

Im Gegensatz zu den üblichen Routern in SPAs geht der TanStack Router einen anderen Weg, wie Sie ihn eher von Fullstack-Frameworks wie Next.js oder Remix kennen. Die offizielle Empfehlung aus der Dokumentation des TanStack Router lautet, dass das dateibasierte Routing der bevorzugte Weg für die Konfiguration des Routers ist. Damit das dateibasierte Routing funktioniert, benötigt der Router ein entsprechend konfiguriertes Build-System. Der TanStack Router funktioniert am besten mit Vite als Build-System und stellt dafür das Plug-in @tanstack/router-vite-plugin zur Verfügung, das Sie als Erweiterung in die Plug-in-Sektion der vite.config.ts-Datei eintragen müssen.

Im nächsten Schritt erzeugen Sie die Dateien für die verschiedenen Routen. Dabei gibt es drei unterschiedliche Kategorien von Routen. Die Applikation verfügt über genau eine Root-Route, die Sie mit createRootRoute erstellen, und beliebig viele File-Routen. Diese integriert das Vite-Build-System entweder direkt in das Applikations-Bundle, wenn Sie zur Erstellung die createFileRoute-Funktion nutzen, oder sie werden in einem separaten Bundle erzeugt und bei Bedarf nachgeladen, wenn Sie sie mit der createLazyFileRoute erzeugen.

Die Root-Route ist der Einstieg in den Komponentenbaum (Listing 1). Diese Route hat keinen zugeordneten Pfad und wird immer aktiviert, also die zugehörige Komponente auch immer gerendert. Dabei ist sie eine vollwertige Route, in deren Komponente Sie Zugriff auf den vollen Funktionsumfang des Routers haben. Alle Dateien, die mit der Routenkonfiguration zu tun haben, legen Sie in einem Verzeichnis mit dem Namen routes im src-Verzeichnis Ihrer Applikation ab. Die Root-Route erzeugen Sie mit einem Aufruf der createRootRoute-Funktion, der Sie ein Objekt vom Typ RouteOptions übergeben. Im einfachsten Fall können Sie die createRootRoute-Funktion auch ganz ohne Argument aufrufen. In diesem Fall rendert der Router nur die Outlet-Komponente des TanStack Router, in die der Router die Ergebnisse der untergeordneten Routen einfügt. Für die Root-Route gibt es eine klare Regel, was die Benennung und den Speicherort der Datei angeht: Der Name der Datei lautet __root.tsx und sie muss im routesDirectory, das standardmäßig das src/routes-Verzeichnis ist, liegen. In der Datei exportieren Sie dann das Routenobjekt in einer Konstante mit dem Namen Route. Diese Namenskonvention zieht sich übrigens durch alle Routendefinitionen.

Listing 1: Code der Root-Route (src/routes/__root.tsx)

import { createRootRoute } from '@tanstack/react-router';

export const Route = createRootRoute();

Neben der Root-Route benötigen Sie noch weitere Routen, die sich dann darum kümmern, den jeweiligen Inhalt zu rendern. Als konkretes Beispiel nutzen wir hier eine Applikation zur Verwaltung von Büchern mit einer Komponente zur Darstellung aller existierenden Datensätze und einem Formular zum Anlegen und Bearbeiten von Datensätzen. Also benötigen wir zwei neue Routen: die /list-Route, die Sie in der Datei src/routes/list.tsx speichern, und die /form-Route, die in der Datei src/routes/form/index.tsx liegt. Wie Sie hier schon erkennen können, unterstützt der TanStack Router zwei unterschiedliche Ansätze beim Ablegen von Routen. Sie können die Routendateien entweder als Flat Routes in einer flachen Struktur ablegen und die Pfade mit dem Dateinamen modellieren oder Sie legen die Dateien in einer tieferen Struktur, den Route Trees, ab, bei der der Pfadname den URL-Pfad abbildet. Theoretisch können Sie, wie im Beispiel, beide Ansätze auch miteinander verknüpfen. Hierbei sollten Sie allerdings vorsichtig sein, damit die Routenkonfiguration verständlich bleibt.

Nun geht es an die Implementierung der beiden Routen. Ein Aufruf der createFileRoute-Funktion erzeugt wiederum eine Funktion, der Sie die Routenkonfiguration übergeben können. Diese verschachtelten Funktionsaufrufe sind erforderlich, damit TypeScript mitgeteilt werden kann, für welche Route die aktuelle Datei zuständig ist. Diese Information kann der Router zwar aus dem Pfad- und Dateinamen ableiten, TypeScript jedoch nicht. Sie müssen sich jedoch nicht zwingend um diesen Pfad kümmern. Läuft der Dev-Server von Vite im Hintergrund, aktualisiert das Router-Plug-in den Pfad automatisch für Sie anhand der Information aus dem Dateisystem. Damit ist sichergestellt, dass Dateisystem und Code immer synchron sind.

Die zweite Funktion in dieser Reihe akzeptiert ein Konfigurationsobjekt, das mindestens eine component-Eigenschaft benötigt, die eine gültige React-Komponente enthält. Sie können diese Komponente entweder inline im Objekt definieren oder, wie in Listing 2 zu sehen ist, als separate Komponentenfunktion. Das hat den Vorteil, dass die Routenkonfiguration lesbarer bleibt.

Listing 2: Die /list-Route

import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/list')({
  component: ListComponent,
});

function ListComponent() {
  return (
    <div>
      <h1>List works</h1>
    </div>
  );
}

Die ListComponent, also die Komponente hinter der /list-Route, verfügt über einen eigenen State und lädt mit Hilfe eines Aufrufs der useEffect-Funktion beim initialen Rendern die Daten für die Anzeige vom Server. Diese Daten zeigt die Komponente dann in Form einer Liste an. Damit die Liste auch korrekt angezeigt wird, fehlt nur noch die Integration in die Applikation. Das erfolgt üblicherweise im Einstieg, also in der main.tsx-Datei. Im ersten Schritt erzeugen Sie mit der createRouter-Funktion eine neue Router-Instanz. Auch hier arbeiten Sie wieder mit einem...