Framework
Version
Integrationen

Codebasierte Routen

Tipp

Code-basiertes Routing wird für die meisten Anwendungen nicht empfohlen. Es wird empfohlen, stattdessen Datei-basiertes Routing zu verwenden.

⚠️ Bevor Sie beginnen

  • Wenn Sie Datei-basiertes Routing verwenden, überspringen Sie diese Anleitung.
  • Wenn Sie dennoch codebasiertes Routing verwenden möchten, müssen Sie zuerst die Anleitung Routing-Konzepte lesen, da diese auch Kernkonzepte des Routers behandelt.

Routenbäume

Code-basiertes Routing unterscheidet sich nicht von dateibasiertem Routing darin, dass es dasselbe Routenbaumkonzept verwendet, um passende Routen zu organisieren, abzugleichen und in einen Komponentenbaum zu integrieren. Der einzige Unterschied besteht darin, dass Sie anstelle des Dateisystems zum Organisieren Ihrer Routen Code verwenden.

Betrachten wir denselben Routenbaum aus der Anleitung Routenbäume & Verschachtelung und wandeln ihn in codebasiertes Routing um

Hier ist die dateibasierte Version

routes/
├── __root.tsx
├── index.tsx
├── about.tsx
├── posts/
│   ├── index.tsx
│   ├── $postId.tsx
├── posts.$postId.edit.tsx
├── settings/
│   ├── profile.tsx
│   ├── notifications.tsx
├── _pathlessLayout.tsx
├── _pathlessLayout/
│   ├── route-a.tsx
├── ├── route-b.tsx
├── files/
│   ├── $.tsx
routes/
├── __root.tsx
├── index.tsx
├── about.tsx
├── posts/
│   ├── index.tsx
│   ├── $postId.tsx
├── posts.$postId.edit.tsx
├── settings/
│   ├── profile.tsx
│   ├── notifications.tsx
├── _pathlessLayout.tsx
├── _pathlessLayout/
│   ├── route-a.tsx
├── ├── route-b.tsx
├── files/
│   ├── $.tsx

Und hier ist eine zusammengefasste codebasierte Version

tsx
import { createRootRoute, createRoute } from '@tanstack/react-router'

const rootRoute = createRootRoute()

const indexRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/',
})

const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'about',
})

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
})

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '/',
})

const postRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
})

const postEditorRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts/$postId/edit',
})

const settingsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'settings',
})

const profileRoute = createRoute({
  getParentRoute: () => settingsRoute,
  path: 'profile',
})

const notificationsRoute = createRoute({
  getParentRoute: () => settingsRoute,
  path: 'notifications',
})

const pathlessLayoutRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: 'pathlessLayout',
})

const pathlessLayoutARoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-a',
})

const pathlessLayoutBRoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-b',
})

const filesRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'files/$',
})
import { createRootRoute, createRoute } from '@tanstack/react-router'

const rootRoute = createRootRoute()

const indexRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/',
})

const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'about',
})

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
})

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '/',
})

const postRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
})

const postEditorRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts/$postId/edit',
})

const settingsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'settings',
})

const profileRoute = createRoute({
  getParentRoute: () => settingsRoute,
  path: 'profile',
})

const notificationsRoute = createRoute({
  getParentRoute: () => settingsRoute,
  path: 'notifications',
})

const pathlessLayoutRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: 'pathlessLayout',
})

const pathlessLayoutARoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-a',
})

const pathlessLayoutBRoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-b',
})

const filesRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'files/$',
})

Anatomie einer Route

Alle anderen Routen außer der Root-Route werden mit der Funktion createRoute konfiguriert

tsx
const route = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts',
  component: PostsComponent,
})
const route = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts',
  component: PostsComponent,
})

Die Option getParentRoute ist eine Funktion, die die übergeordnete Route der zu erstellenden Route zurückgibt.

❓❓❓ "Moment, Sie lassen mich die übergeordnete Route für jede von mir erstellte Route übergeben?"

Absolut! Der Grund für die Übergabe der übergeordneten Route hat alles mit der magischen Typsicherheit von TanStack Router zu tun. Ohne die übergeordnete Route wüsste TypeScript nicht, welche Typen es Ihrer Route zuweisen soll!

Wichtig

Für jede Route, die NICHT die Root-Route oder eine Pfadlose Layout-Route ist, ist eine path-Option erforderlich. Dies ist der Pfad, der mit dem URL-Pfad abgeglichen wird, um zu bestimmen, ob die Route eine Übereinstimmung ist.

Wenn Sie die path-Option auf einer Route konfigurieren, ignoriert diese führende und nachgestellte Schrägstriche (dies schließt "Index"-Routenpfade / nicht ein). Sie können sie einfügen, wenn Sie möchten, aber sie werden intern von TanStack Router normalisiert. Hier ist eine Tabelle mit gültigen Pfaden und wie sie normalisiert werden

PfadNormalisierter Pfad
//
/aboutabout
about/about
aboutabout
$$
/$$
/$/$

Manuelles Erstellen des Routenbaums

Beim Erstellen eines Routenbaums im Code reicht es nicht aus, die übergeordnete Route jeder Route zu definieren. Sie müssen auch den endgültigen Routenbaum erstellen, indem Sie jede Route zum children-Array ihrer übergeordneten Route hinzufügen. Dies liegt daran, dass der Routenbaum nicht automatisch für Sie erstellt wird, wie es beim dateibasierten Routing der Fall ist.

tsx
/* prettier-ignore */
const routeTree = rootRoute.addChildren([
  indexRoute,
  aboutRoute,
  postsRoute.addChildren([
    postsIndexRoute,
    postRoute,
  ]),
  postEditorRoute,
  settingsRoute.addChildren([
    profileRoute,
    notificationsRoute,
  ]),
  pathlessLayoutRoute.addChildren([
    pathlessLayoutARoute,
    pathlessLayoutBRoute,
  ]),
  filesRoute.addChildren([
    fileRoute,
  ]),
])
/* prettier-ignore-end */
/* prettier-ignore */
const routeTree = rootRoute.addChildren([
  indexRoute,
  aboutRoute,
  postsRoute.addChildren([
    postsIndexRoute,
    postRoute,
  ]),
  postEditorRoute,
  settingsRoute.addChildren([
    profileRoute,
    notificationsRoute,
  ]),
  pathlessLayoutRoute.addChildren([
    pathlessLayoutARoute,
    pathlessLayoutBRoute,
  ]),
  filesRoute.addChildren([
    fileRoute,
  ]),
])
/* prettier-ignore-end */

Aber bevor Sie den Routenbaum erstellen können, müssen Sie verstehen, wie die Routing-Konzepte für codebasiertes Routing funktionieren.

Routing-Konzepte für Code-basiertes Routing

Glauben Sie es oder nicht, dateibasiertes Routing ist wirklich eine Obermenge des codebasierten Routings und verwendet das Dateisystem und eine kleine Code-Generierungsabstraktion darüber, um diese oben gezeigte Struktur automatisch zu generieren.

Wir gehen davon aus, dass Sie die Anleitung Routing-Konzepte gelesen haben und mit jedem dieser Hauptkonzepte vertraut sind

  • Die Root-Route
  • Basics Routen
  • Index-Routen
  • Dynamische Routensegmente
  • Splat / Catch-All Routen
  • Layout-Routen
  • Pfadlose Routen
  • Nicht-verschachtelte Routen

Sehen wir uns nun an, wie jede dieser Routentypen im Code erstellt wird.

Die Root-Route

Das Erstellen einer Root-Route im codebasierten Routing ist glücklicherweise dasselbe wie beim dateibasierten Routing. Rufen Sie die Funktion createRootRoute() auf.

Im Gegensatz zum dateibasierten Routing müssen Sie die Root-Route nicht exportieren, wenn Sie nicht möchten. Es ist sicherlich nicht ratsam, einen ganzen Routenbaum und eine Anwendung in einer einzigen Datei zu erstellen (obwohl Sie dies tun können und wir es in den Beispielen tun, um Routing-Konzepte kurz zu demonstrieren).

tsx
// Standard root route
import { createRootRoute } from '@tanstack/react-router'

const rootRoute = createRootRoute()

// Root route with Context
import { createRootRouteWithContext } from '@tanstack/react-router'
import type { QueryClient } from '@tanstack/react-query'

export interface MyRouterContext {
  queryClient: QueryClient
}
const rootRoute = createRootRouteWithContext<MyRouterContext>()
// Standard root route
import { createRootRoute } from '@tanstack/react-router'

const rootRoute = createRootRoute()

// Root route with Context
import { createRootRouteWithContext } from '@tanstack/react-router'
import type { QueryClient } from '@tanstack/react-query'

export interface MyRouterContext {
  queryClient: QueryClient
}
const rootRoute = createRootRouteWithContext<MyRouterContext>()

Um mehr über Kontext in TanStack Router zu erfahren, siehe die Anleitung Router Context.

Basics Routen

Um eine einfache Route zu erstellen, übergeben Sie einfach einen normalen path-String an die Funktion createRoute

tsx
const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'about',
})
const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'about',
})

Sehen Sie, so einfach ist das! Die aboutRoute stimmt mit der URL /about überein.

Index-Routen

Im Gegensatz zum dateibasierten Routing, das den index-Dateinamen verwendet, um eine Index-Route zu bezeichnen, verwendet codebasiertes Routing einen einzelnen Schrägstrich /, um eine Index-Route zu bezeichnen. Zum Beispiel würde die Datei posts.index.tsx aus unserem obigen Beispiel-Routenbaum im codebasierten Routing wie folgt dargestellt werden

tsx
const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
})

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  // Notice the single slash `/` here
  path: '/',
})
const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
})

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  // Notice the single slash `/` here
  path: '/',
})

Die postsIndexRoute stimmt also mit der URL /posts/ (oder /posts) überein.

Dynamische Routensegmente

Dynamische Routensegmente funktionieren im codebasierten Routing genau wie im dateibasierten Routing. Präfixen Sie einfach ein Segment des Pfads mit einem $ und es wird in das params-Objekt des loader oder component der Route erfasst werden

tsx
const postIdRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
  // In a loader
  loader: ({ params }) => fetchPost(params.postId),
  // Or in a component
  component: PostComponent,
})

function PostComponent() {
  const { postId } = postIdRoute.useParams()
  return <div>Post ID: {postId}</div>
}
const postIdRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
  // In a loader
  loader: ({ params }) => fetchPost(params.postId),
  // Or in a component
  component: PostComponent,
})

function PostComponent() {
  const { postId } = postIdRoute.useParams()
  return <div>Post ID: {postId}</div>
}

Tipp

Wenn Ihre Komponente code-gesplittet ist, können Sie die getRouteApi-Funktion verwenden, um den Import der postIdRoute-Konfiguration zu vermeiden, um Zugriff auf den typisierten useParams()-Hook zu erhalten.

Splat / Catch-All Routen

Wie erwartet funktionieren Splat/Catch-all-Routen auch im codebasierten Routing wie im dateibasierten Routing. Präfixen Sie einfach ein Segment des Pfads mit einem $ und es wird in das params-Objekt unter dem Schlüssel _splat erfasst werden

tsx
const filesRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'files',
})

const fileRoute = createRoute({
  getParentRoute: () => filesRoute,
  path: '$',
})
const filesRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'files',
})

const fileRoute = createRoute({
  getParentRoute: () => filesRoute,
  path: '$',
})

Für die URL /documents/hello-world sieht das params-Objekt so aus

js
{
  '_splat': 'documents/hello-world'
}
{
  '_splat': 'documents/hello-world'
}

Layout-Routen

Layout-Routen sind Routen, die ihre Kinder in eine Layout-Komponente einschließen. Im codebasierten Routing können Sie eine Layout-Route erstellen, indem Sie einfach eine Route unter einer anderen Route verschachteln

tsx
const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
  component: PostsLayoutComponent, // The layout component
})

function PostsLayoutComponent() {
  return (
    <div>
      <h1>Posts</h1>
      <Outlet />
    </div>
  )
}

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '/',
})

const postsCreateRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: 'create',
})

const routeTree = rootRoute.addChildren([
  // The postsRoute is the layout route
  // Its children will be nested under the PostsLayoutComponent
  postsRoute.addChildren([postsIndexRoute, postsCreateRoute]),
])
const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
  component: PostsLayoutComponent, // The layout component
})

function PostsLayoutComponent() {
  return (
    <div>
      <h1>Posts</h1>
      <Outlet />
    </div>
  )
}

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '/',
})

const postsCreateRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: 'create',
})

const routeTree = rootRoute.addChildren([
  // The postsRoute is the layout route
  // Its children will be nested under the PostsLayoutComponent
  postsRoute.addChildren([postsIndexRoute, postsCreateRoute]),
])

Nun rendern sowohl die postsIndexRoute als auch die postsCreateRoute ihre Inhalte innerhalb der PostsLayoutComponent

tsx
// URL: /posts
<PostsLayoutComponent>
  <PostsIndexComponent />
</PostsLayoutComponent>

// URL: /posts/create
<PostsLayoutComponent>
  <PostsCreateComponent />
</PostsLayoutComponent>
// URL: /posts
<PostsLayoutComponent>
  <PostsIndexComponent />
</PostsLayoutComponent>

// URL: /posts/create
<PostsLayoutComponent>
  <PostsCreateComponent />
</PostsLayoutComponent>

Pfadlose Layout-Routen

Im dateibasierten Routing wird eine pfadloses Layout-Route mit einem _ als Präfix versehen, aber im codebasierten Routing ist dies einfach eine Route mit einer id anstelle einer path-Option. Das liegt daran, dass codebasiertes Routing das Dateisystem nicht zur Organisation von Routen verwendet, daher ist es nicht notwendig, eine Route mit einem _ zu präfixen, um anzuzeigen, dass sie keinen Pfad hat.

tsx
const pathlessLayoutRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: 'pathlessLayout',
  component: PathlessLayoutComponent,
})

function PathlessLayoutComponent() {
  return (
    <div>
      <h1>Pathless Layout</h1>
      <Outlet />
    </div>
  )
}

const pathlessLayoutARoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-a',
})

const pathlessLayoutBRoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-b',
})

const routeTree = rootRoute.addChildren([
  // The pathless layout route has no path, only an id
  // So its children will be nested under the pathless layout route
  pathlessLayoutRoute.addChildren([pathlessLayoutARoute, pathlessLayoutBRoute]),
])
const pathlessLayoutRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: 'pathlessLayout',
  component: PathlessLayoutComponent,
})

function PathlessLayoutComponent() {
  return (
    <div>
      <h1>Pathless Layout</h1>
      <Outlet />
    </div>
  )
}

const pathlessLayoutARoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-a',
})

const pathlessLayoutBRoute = createRoute({
  getParentRoute: () => pathlessLayoutRoute,
  path: 'route-b',
})

const routeTree = rootRoute.addChildren([
  // The pathless layout route has no path, only an id
  // So its children will be nested under the pathless layout route
  pathlessLayoutRoute.addChildren([pathlessLayoutARoute, pathlessLayoutBRoute]),
])

Nun rendern sowohl /route-a als auch /route-b ihre Inhalte innerhalb der PathlessLayoutComponent

tsx
// URL: /route-a
<PathlessLayoutComponent>
  <RouteAComponent />
</PathlessLayoutComponent>

// URL: /route-b
<PathlessLayoutComponent>
  <RouteBComponent />
</PathlessLayoutComponent>
// URL: /route-a
<PathlessLayoutComponent>
  <RouteAComponent />
</PathlessLayoutComponent>

// URL: /route-b
<PathlessLayoutComponent>
  <RouteBComponent />
</PathlessLayoutComponent>

Nicht-verschachtelte Routen

Das Erstellen nicht verschachtelter Routen im codebasierten Routing erfordert nicht die Verwendung eines nachgestellten _ im Pfad, erfordert jedoch, dass Sie Ihre Route und Ihren Routenbaum mit den richtigen Pfaden und Verschachtelungen erstellen. Betrachten wir den Routenbaum, bei dem der Beitragseditor nicht unter der Beiträge-Route verschachtelt sein soll

  • /posts_/$postId/edit
  • /posts
    • $postId

Um dies zu tun, müssen wir eine separate Route für den Beitragseditor erstellen und den gesamten Pfad in der path-Option vom Stammverzeichnis aus einfügen, wo die Route verschachtelt werden soll (in diesem Fall das Stammverzeichnis)

tsx
// The posts editor route is nested under the root route
const postEditorRoute = createRoute({
  getParentRoute: () => rootRoute,
  // The path includes the entire path we need to match
  path: 'posts/$postId/edit',
})

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
})

const postRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
})

const routeTree = rootRoute.addChildren([
  // The post editor route is nested under the root route
  postEditorRoute,
  postsRoute.addChildren([postRoute]),
])
// The posts editor route is nested under the root route
const postEditorRoute = createRoute({
  getParentRoute: () => rootRoute,
  // The path includes the entire path we need to match
  path: 'posts/$postId/edit',
})

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
})

const postRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
})

const routeTree = rootRoute.addChildren([
  // The post editor route is nested under the root route
  postEditorRoute,
  postsRoute.addChildren([postRoute]),
])
Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.