Tipp
Codebasierte Routenführung wird für die meisten Anwendungen nicht empfohlen. Es wird empfohlen, stattdessen die dateibasierte Routenführung zu verwenden.
Codebasierte Routenführung unterscheidet sich nicht von dateibasierter Routenführung darin, dass sie dasselbe Routenbaumkonzept verwendet, um passende Routen zu organisieren, abzugleichen und zu einer Komponentenstruktur zusammenzusetzen. Der einzige Unterschied besteht darin, dass anstelle des Dateisystems zur Organisation Ihrer Routen der Code verwendet wird.
Betrachten wir denselben Routenbaum aus der Anleitung Routenbäume & Verschachtelung und wandeln Sie ihn in eine codebasierte Routenführung 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
import { createRootRoute, createRoute } from '@tanstack/solid-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/solid-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/$',
})
Alle Routen außer der Root-Route werden mit der Funktion createRoute konfiguriert.
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 Elternroute der von Ihnen erstellten Route zurückgibt.
❓❓❓ "Warten Sie, Sie lassen mich die Elternroute für jede von mir erstellte Route übergeben?"
Absolut! Der Grund für die Übergabe der Elternroute hat **alles mit der magischen Typsicherheit** von TanStack Router zu tun. Ohne die Elternroute hätte TypeScript keine Ahnung, welche Typen Ihrer Route zugewiesen werden sollen!
Wichtig
Für jede Route, die **NICHT** die **Root-Route** oder eine **pfadlose Layout-Route** ist, ist eine Option path erforderlich. Dies ist der Pfad, der mit dem URL-Pfad abgeglichen wird, um festzustellen, ob die Route übereinstimmt.
Wenn Sie die Routenoption path für eine Route konfigurieren, werden führende und nachgestellte Schrägstriche ignoriert (dies schließt Pfade von "Index"-Routen / nicht ein). Sie können sie einschließen, wenn Sie möchten, aber sie werden intern von TanStack Router normalisiert. Hier ist eine Tabelle mit gültigen Pfaden und deren Normalisierung.
| Pfad | Normalisierter Pfad |
|---|---|
| / | / |
| /about | about |
| about/ | about |
| about | about |
| $ | $ |
| /$ | $ |
| /$/ | $ |
Beim Erstellen eines Routenbaums im Code reicht es nicht aus, die Elternroute jeder Route zu definieren. Sie müssen auch den endgültigen Routenbaum konstruieren, indem Sie jede Route dem Array children ihrer Elternroute hinzufügen. Dies liegt daran, dass der Routenbaum nicht automatisch für Sie erstellt wird, wie es bei der dateibasierten Routenführung der Fall ist.
/* 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 codebasierte Routenführung funktionieren.
Glauben Sie es oder nicht, die dateibasierte Routenführung ist eigentlich eine Obermenge der codebasierten Routenführung und verwendet das Dateisystem und ein wenig Code-Generierungs-Abstraktion 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.
Nun wollen wir uns ansehen, wie jede dieser Routentypen im Code erstellt wird.
Das Erstellen einer Root-Route in der codebasierten Routenführung ist glücklicherweise dasselbe wie bei der dateibasierten Routenführung. Rufen Sie die Funktion createRootRoute() auf.
Im Gegensatz zur dateibasierten Routenführung müssen Sie die Root-Route jedoch nicht exportieren, wenn Sie dies nicht möchten. Es wird sicherlich nicht empfohlen, einen gesamten Routenbaum und eine Anwendung in einer einzigen Datei zu erstellen (obwohl Sie dies tun können und wir es in den Beispielen tun, um die Routing-Konzepte kurz zu demonstrieren).
// Standard root route
import { createRootRoute } from '@tanstack/solid-router'
const rootRoute = createRootRoute()
// Root route with Context
import { createRootRouteWithContext } from '@tanstack/solid-router'
import type { QueryClient } from '@tanstack/react-query'
export interface MyRouterContext {
queryClient: QueryClient
}
const rootRoute = createRootRouteWithContext<MyRouterContext>()
// Standard root route
import { createRootRoute } from '@tanstack/solid-router'
const rootRoute = createRootRoute()
// Root route with Context
import { createRootRouteWithContext } from '@tanstack/solid-router'
import type { QueryClient } from '@tanstack/react-query'
export interface MyRouterContext {
queryClient: QueryClient
}
const rootRoute = createRootRouteWithContext<MyRouterContext>()
Um mehr über den Kontext in TanStack Router zu erfahren, lesen Sie die Anleitung Router Context.
Um eine einfache Route zu erstellen, übergeben Sie einfach einen normalen path-String an die Funktion createRoute.
const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: 'about',
})
const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: 'about',
})
Sehen Sie, es ist so einfach! Die aboutRoute wird mit der URL /about übereinstimmen.
Im Gegensatz zur dateibasierten Routenführung, die den Dateinamen index verwendet, um eine Index-Route zu kennzeichnen, verwendet die codebasierte Routenführung einen einzelnen Schrägstrich /, um eine Index-Route zu kennzeichnen. Zum Beispiel würde die Datei posts.index.tsx aus unserem obigen Beispiel-Routenbaum in der codebasierten Routenführung wie folgt dargestellt werden:
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 wird also mit der URL /posts/ (oder /posts) übereinstimmen.
Dynamische Routensegmente funktionieren in der codebasierten Routenführung genau wie in der dateibasierten Routenführung. Präfixen Sie einfach ein Segment des Pfads mit einem $, und es wird im params-Objekt des loader oder der component der Route erfasst.
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 Funktion getRouteApi verwenden, um den Import der Konfiguration postIdRoute zu vermeiden und so Zugriff auf den typisierten useParams()-Hook zu erhalten.
Wie erwartet funktionieren Splat/Catch-all-Routen in der codebasierten Routenführung genauso wie in der dateibasierten Routenführung. Präfixen Sie einfach ein Segment des Pfads mit einem $, und es wird im params-Objekt unter dem Schlüssel _splat erfasst.
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 wird das params-Objekt wie folgt aussehen:
{
'_splat': 'documents/hello-world'
}
{
'_splat': 'documents/hello-world'
}
Layout-Routen sind Routen, die ihre Kinder in eine Layout-Komponente einpacken. In der codebasierten Routenführung können Sie eine Layout-Route erstellen, indem Sie einfach eine Route unter einer anderen Route verschachteln.
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 werden sowohl die postsIndexRoute als auch die postsCreateRoute ihre Inhalte innerhalb der PostsLayoutComponent rendern.
// URL: /posts
<PostsLayoutComponent>
<PostsIndexComponent />
</PostsLayoutComponent>
// URL: /posts/create
<PostsLayoutComponent>
<PostsCreateComponent />
</PostsLayoutComponent>
// URL: /posts
<PostsLayoutComponent>
<PostsIndexComponent />
</PostsLayoutComponent>
// URL: /posts/create
<PostsLayoutComponent>
<PostsCreateComponent />
</PostsLayoutComponent>
In der dateibasierten Routenführung wird eine pfadlose Layout-Route mit einem Präfix _ versehen, aber in der codebasierten Routenführung handelt es sich einfach um eine Route mit einer id anstelle einer Option path. Dies liegt daran, dass die codebasierte Routenführung das Dateisystem nicht zur Organisation von Routen verwendet, sodass keine Notwendigkeit besteht, eine Route mit einem _ zu präfixieren, um anzuzeigen, dass sie keinen Pfad hat.
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 werden sowohl /route-a als auch /route-b ihre Inhalte innerhalb der PathlessLayoutComponent rendern.
// URL: /route-a
<PathlessLayoutComponent>
<RouteAComponent />
</PathlessLayoutComponent>
// URL: /route-b
<PathlessLayoutComponent>
<RouteBComponent />
</PathlessLayoutComponent>
// URL: /route-a
<PathlessLayoutComponent>
<RouteAComponent />
</PathlessLayoutComponent>
// URL: /route-b
<PathlessLayoutComponent>
<RouteBComponent />
</PathlessLayoutComponent>
Das Erstellen von nicht verschachtelten Routen in der codebasierten Routenführung 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 Post-Editor **nicht** unter der Posts-Route verschachtelt sein soll.
Um dies zu erreichen, müssen wir eine separate Route für den Post-Editor erstellen und den gesamten Pfad in der Option path vom Ursprung des Ortes aus angeben, an dem die Route verschachtelt werden soll (in diesem Fall der Root).
// 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]),
])
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.