Pfadparameter werden verwendet, um ein einzelnes Segment (den Text bis zum nächsten /) abzugleichen und dessen Wert als **benannten** Variablennamen zurückzugeben. Sie werden definiert, indem ein Dollarzeichen $-Präfix im Pfad verwendet wird, gefolgt von dem Schlüsselnamen, dem der Wert zugewiesen werden soll. Die folgenden sind gültige Pfadparameterpfade
Da Pfadparameterrouten nur bis zum nächsten / abgeglichen werden, können untergeordnete Routen erstellt werden, um die Hierarchie weiter auszudrücken
Erstellen wir eine Post-Routendatei, die einen Pfadparameter verwendet, um die Post-ID abzugleichen
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
return fetchPost(params.postId)
},
})
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
return fetchPost(params.postId)
},
})
Sobald ein Pfadparameter analysiert wurde, steht er allen untergeordneten Routen zur Verfügung. Das bedeutet, dass, wenn wir eine untergeordnete Route zu unserer postRoute definieren, wir die postId-Variable aus der URL in der Route des Kindes verwenden können!
Pfadparameter werden als params-Objekt an den Loader übergeben. Die Schlüssel dieses Objekts sind die Namen der Pfadparameter und die Werte sind die Werte, die aus dem tatsächlichen URL-Pfad analysiert wurden. Wenn wir beispielsweise die URL /blog/123 besuchen würden, wäre das params-Objekt { postId: '123' }
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
return fetchPost(params.postId)
},
})
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
return fetchPost(params.postId)
},
})
Das params-Objekt wird auch an die beforeLoad-Option übergeben
export const Route = createFileRoute('/posts/$postId')({
beforeLoad: async ({ params }) => {
// do something with params.postId
},
})
export const Route = createFileRoute('/posts/$postId')({
beforeLoad: async ({ params }) => {
// do something with params.postId
},
})
Wenn wir unserer postRoute eine Komponente hinzufügen, können wir die postId-Variable aus der URL abrufen, indem wir den useParams-Hook der Route verwenden
export const Route = createFileRoute('/posts/$postId')({
component: PostComponent,
})
function PostComponent() {
const params = Route.useParams()
return <div>Post {params.postId()}</div>
}
export const Route = createFileRoute('/posts/$postId')({
component: PostComponent,
})
function PostComponent() {
const params = Route.useParams()
return <div>Post {params.postId()}</div>
}
🧠 Schneller Tipp: Wenn Ihre Komponente code-split ist, können Sie die Funktion getRouteApi verwenden, um zu vermeiden, dass Sie die Route-Konfiguration importieren müssen, um Zugriff auf den typisierten useParams()-Hook zu erhalten.
Sie können auch den global exportierten useParams-Hook verwenden, um auf alle analysierten Pfadparameter von jeder Komponente in Ihrer App zuzugreifen. Sie müssen die Option strict: false an useParams übergeben, was darauf hinweist, dass Sie von einem mehrdeutigen Ort auf die Parameter zugreifen möchten
function PostComponent() {
const { postId } = useParams({ strict: false })
return <div>Post {params.postId()}</div>
}
function PostComponent() {
const { postId } = useParams({ strict: false })
return <div>Post {params.postId()}</div>
}
Beim Navigieren zu einer Route mit Pfadparametern verlangt TypeScript, dass Sie die Parameter entweder als Objekt oder als Funktion, die ein Objekt von Parametern zurückgibt, übergeben.
Sehen wir uns an, wie ein Objektstil aussieht
function Component() {
return (
<Link to="/blog/$postId" params={{ postId: '123' }}>
Post 123
</Link>
)
}
function Component() {
return (
<Link to="/blog/$postId" params={{ postId: '123' }}>
Post 123
</Link>
)
}
Und hier ist, wie ein Funktionsstil aussieht
function Component() {
return (
<Link to="/blog/$postId" params={(prev) => ({ ...prev, postId: '123' })}>
Post 123
</Link>
)
}
function Component() {
return (
<Link to="/blog/$postId" params={(prev) => ({ ...prev, postId: '123' })}>
Post 123
</Link>
)
}
Beachten Sie, dass der Funktionsstil nützlich ist, wenn Sie Parameter beibehalten müssen, die sich bereits in der URL für andere Routen befinden. Dies liegt daran, dass der Funktionsstil die aktuellen Parameter als Argument erhält, sodass Sie sie nach Bedarf ändern und das endgültige Parameterobjekt zurückgeben können.
Sie können auch **Präfixe** und **Suffixe** mit Pfadparametern verwenden, um komplexere Routingmuster zu erstellen. Dies ermöglicht es Ihnen, bestimmte URL-Strukturen abzugleichen und gleichzeitig die dynamischen Segmente zu erfassen.
Bei Verwendung von Präfixen oder Suffixen können Sie diese definieren, indem Sie den Pfadparameter in geschweifte Klammern {} einschließen und das Präfix oder Suffix vor oder nach dem Variablennamen platzieren.
Präfixe werden definiert, indem der Präfixtext außerhalb der geschweiften Klammern vor dem Variablennamen platziert wird. Wenn Sie beispielsweise eine URL abgleichen möchten, die mit post- gefolgt von einer Post-ID beginnt, können Sie sie wie folgt definieren
// src/routes/posts/post-{$postId}.tsx
export const Route = createFileRoute('/posts/post-{$postId}')({
component: PostComponent,
})
function PostComponent() {
const params = Route.useParams()
// postId will be the value after 'post-'
return <div>Post ID: {params.postId()}</div>
}
// src/routes/posts/post-{$postId}.tsx
export const Route = createFileRoute('/posts/post-{$postId}')({
component: PostComponent,
})
function PostComponent() {
const params = Route.useParams()
// postId will be the value after 'post-'
return <div>Post ID: {params.postId()}</div>
}
Sie können sogar Präfixe mit Wildcard-Routen kombinieren, um komplexere Muster zu erstellen
// src/routes/on-disk/storage-{$}
export const Route = createFileRoute('/on-disk/storage-{$postId}/$')({
component: StorageComponent,
})
function StorageComponent() {
const params = Route.useParams()
// _splat, will be value after 'storage-'
// i.e. my-drive/documents/foo.txt
return <div>Storage Location: /{params._splat()}</div>
}
// src/routes/on-disk/storage-{$}
export const Route = createFileRoute('/on-disk/storage-{$postId}/$')({
component: StorageComponent,
})
function StorageComponent() {
const params = Route.useParams()
// _splat, will be value after 'storage-'
// i.e. my-drive/documents/foo.txt
return <div>Storage Location: /{params._splat()}</div>
}
Suffixe werden definiert, indem der Suffixtext außerhalb der geschweiften Klammern nach dem Variablennamen platziert wird. Wenn Sie beispielsweise eine URL abgleichen möchten, die mit txt endet, können Sie sie wie folgt definieren
// src/routes/files/{$fileName}txt
export const Route = createFileRoute('/files/{$fileName}.txt')({
component: FileComponent,
})
function FileComponent() {
const params = Route.useParams()
// fileName will be the value before 'txt'
return <div>File Name: {params.userId()}</div>
}
// src/routes/files/{$fileName}txt
export const Route = createFileRoute('/files/{$fileName}.txt')({
component: FileComponent,
})
function FileComponent() {
const params = Route.useParams()
// fileName will be the value before 'txt'
return <div>File Name: {params.userId()}</div>
}
Sie können auch Suffixe mit Wildcards kombinieren, um komplexere Routingmuster zu erstellen
// src/routes/files/{$}[.]txt
export const Route = createFileRoute('/files/{$fileName}[.]txt')({
component: FileComponent,
})
function FileComponent() {
const params = Route.useParams()
// _splat will be the value before '.txt'
return <div>File Splat: {params._splat()}</div>
}
// src/routes/files/{$}[.]txt
export const Route = createFileRoute('/files/{$fileName}[.]txt')({
component: FileComponent,
})
function FileComponent() {
const params = Route.useParams()
// _splat will be the value before '.txt'
return <div>File Splat: {params._splat()}</div>
}
Sie können sowohl Präfixe als auch Suffixe kombinieren, um sehr spezifische Routingmuster zu erstellen. Wenn Sie beispielsweise eine URL abgleichen möchten, die mit user- beginnt und mit .json endet, können Sie sie wie folgt definieren
// src/routes/users/user-{$userId}person
export const Route = createFileRoute('/users/user-{$userId}person')({
component: UserComponent,
})
function UserComponent() {
const params = Route.useParams()
// userId will be the value between 'user-' and 'person'
return <div>User ID: {params.userId()}</div>
}
// src/routes/users/user-{$userId}person
export const Route = createFileRoute('/users/user-{$userId}person')({
component: UserComponent,
})
function UserComponent() {
const params = Route.useParams()
// userId will be the value between 'user-' and 'person'
return <div>User ID: {params.userId()}</div>
}
Ähnlich wie in den vorherigen Beispielen können Sie auch Wildcards mit Präfixen und Suffixen verwenden. Seien Sie kreativ!
Optionale Pfadparameter ermöglichen es Ihnen, Routensegmente zu definieren, die in der URL vorhanden sein können oder nicht. Sie verwenden die Syntax {-$paramName} und bieten flexible Routing-Muster, bei denen bestimmte Parameter optional sind.
Optionale Pfadparameter werden mit geschweiften Klammern und einem Bindestrich-Präfix definiert: {-$paramName}
// Single optional parameter
// src/routes/posts/{-$category}.tsx
export const Route = createFileRoute('/posts/{-$category}')({
component: PostsComponent,
})
// Multiple optional parameters
// src/routes/posts/{-$category}/{-$slug}.tsx
export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({
component: PostComponent,
})
// Mixed required and optional parameters
// src/routes/users/$id/{-$tab}.tsx
export const Route = createFileRoute('/users/$id/{-$tab}')({
component: UserComponent,
})
// Single optional parameter
// src/routes/posts/{-$category}.tsx
export const Route = createFileRoute('/posts/{-$category}')({
component: PostsComponent,
})
// Multiple optional parameters
// src/routes/posts/{-$category}/{-$slug}.tsx
export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({
component: PostComponent,
})
// Mixed required and optional parameters
// src/routes/users/$id/{-$tab}.tsx
export const Route = createFileRoute('/users/$id/{-$tab}')({
component: UserComponent,
})
Optionale Parameter erstellen flexible URL-Muster
Wenn ein optionaler Parameter in der URL nicht vorhanden ist, ist sein Wert in Ihren Routen-Handlern und Komponenten undefined.
Optionale Parameter funktionieren in Ihren Komponenten genauso wie reguläre Parameter, aber ihre Werte können undefined sein
function PostsComponent() {
const { category } = Route.useParams()
return <div>{category ? `Posts in ${category}` : 'All Posts'}</div>
}
function PostsComponent() {
const { category } = Route.useParams()
return <div>{category ? `Posts in ${category}` : 'All Posts'}</div>
}
Optionale Parameter sind in Loadern verfügbar und können undefined sein
export const Route = createFileRoute('/posts/{-$category}')({
loader: async ({ params }) => {
// params.category might be undefined
return fetchPosts({ category: params.category })
},
})
export const Route = createFileRoute('/posts/{-$category}')({
loader: async ({ params }) => {
// params.category might be undefined
return fetchPosts({ category: params.category })
},
})
Optionale Parameter funktionieren auch in beforeLoad-Handlern
export const Route = createFileRoute('/posts/{-$category}')({
beforeLoad: async ({ params }) => {
if (params.category) {
// Validate category exists
await validateCategory(params.category)
}
},
})
export const Route = createFileRoute('/posts/{-$category}')({
beforeLoad: async ({ params }) => {
if (params.category) {
// Validate category exists
await validateCategory(params.category)
}
},
})
Optionale Parameter unterstützen Präfix- und Suffixmuster
// File route: /files/prefix{-$name}.txt
// Matches: /files/prefix.txt and /files/prefixdocument.txt
export const Route = createFileRoute('/files/prefix{-$name}.txt')({
component: FileComponent,
})
function FileComponent() {
const { name } = Route.useParams()
return <div>File: {name || 'default'}</div>
}
// File route: /files/prefix{-$name}.txt
// Matches: /files/prefix.txt and /files/prefixdocument.txt
export const Route = createFileRoute('/files/prefix{-$name}.txt')({
component: FileComponent,
})
function FileComponent() {
const { name } = Route.useParams()
return <div>File: {name || 'default'}</div>
}
Sie können Routen erstellen, bei denen alle Parameter optional sind
// Route: /{-$year}/{-$month}/{-$day}
// Matches: /, /2023, /2023/12, /2023/12/25
export const Route = createFileRoute('/{-$year}/{-$month}/{-$day}')({
component: DateComponent,
})
function DateComponent() {
const { year, month, day } = Route.useParams()
if (!year) return <div>Select a year</div>
if (!month) return <div>Year: {year}</div>
if (!day)
return (
<div>
Month: {year}/{month}
</div>
)
return (
<div>
Date: {year}/{month}/{day}
</div>
)
}
// Route: /{-$year}/{-$month}/{-$day}
// Matches: /, /2023, /2023/12, /2023/12/25
export const Route = createFileRoute('/{-$year}/{-$month}/{-$day}')({
component: DateComponent,
})
function DateComponent() {
const { year, month, day } = Route.useParams()
if (!year) return <div>Select a year</div>
if (!month) return <div>Year: {year}</div>
if (!day)
return (
<div>
Month: {year}/{month}
</div>
)
return (
<div>
Date: {year}/{month}/{day}
</div>
)
}
Optionale Parameter können mit Wildcards für komplexe Routingmuster kombiniert werden
// Route: /docs/{-$version}/$
// Matches: /docs/extra/path, /docs/v2/extra/path
export const Route = createFileRoute('/docs/{-$version}/$')({
component: DocsComponent,
})
function DocsComponent() {
const { version } = Route.useParams()
const params = Route.useParams()
return (
<div>
Version: {version || 'latest'}
Path: {params._splat()}
</div>
)
}
// Route: /docs/{-$version}/$
// Matches: /docs/extra/path, /docs/v2/extra/path
export const Route = createFileRoute('/docs/{-$version}/$')({
component: DocsComponent,
})
function DocsComponent() {
const { version } = Route.useParams()
const params = Route.useParams()
return (
<div>
Version: {version || 'latest'}
Path: {params._splat()}
</div>
)
}
Beim Navigieren zu Routen mit optionalen Parametern haben Sie eine detaillierte Kontrolle darüber, welche Parameter einbezogen werden sollen
function Navigation() {
return (
<div>
{/* Navigate with optional parameter */}
<Link to="/posts/{-$category}" params={{ category: 'tech' }}>
Tech Posts
</Link>
{/* Navigate without optional parameter */}
<Link to="/posts/{-$category}" params={{ category: undefined }}>
All Posts
</Link>
{/* Navigate with multiple optional parameters */}
<Link
to="/posts/{-$category}/{-$slug}"
params={{ category: 'tech', slug: 'react-tips' }}
>
Specific Post
</Link>
</div>
)
}
function Navigation() {
return (
<div>
{/* Navigate with optional parameter */}
<Link to="/posts/{-$category}" params={{ category: 'tech' }}>
Tech Posts
</Link>
{/* Navigate without optional parameter */}
<Link to="/posts/{-$category}" params={{ category: undefined }}>
All Posts
</Link>
{/* Navigate with multiple optional parameters */}
<Link
to="/posts/{-$category}/{-$slug}"
params={{ category: 'tech', slug: 'react-tips' }}
>
Specific Post
</Link>
</div>
)
}
TypeScript bietet volle Typsicherheit für optionale Parameter
function PostsComponent() {
// TypeScript knows category might be undefined
const { category } = Route.useParams() // category: string | undefined
// Safe navigation
const categoryUpper = category?.toUpperCase()
return <div>{categoryUpper || 'All Categories'}</div>
}
// Navigation is type-safe and flexible
<Link
to="/posts/{-$category}"
params={{ category: 'tech' }} // ✅ Valid - string
>
Tech Posts
</Link>
<Link
to="/posts/{-$category}"
params={{ category: 123 }} // ✅ Valid - number (auto-stringified)
>
Category 123
</Link>
function PostsComponent() {
// TypeScript knows category might be undefined
const { category } = Route.useParams() // category: string | undefined
// Safe navigation
const categoryUpper = category?.toUpperCase()
return <div>{categoryUpper || 'All Categories'}</div>
}
// Navigation is type-safe and flexible
<Link
to="/posts/{-$category}"
params={{ category: 'tech' }} // ✅ Valid - string
>
Tech Posts
</Link>
<Link
to="/posts/{-$category}"
params={{ category: 123 }} // ✅ Valid - number (auto-stringified)
>
Category 123
</Link>
Optionale Pfadparameter sind hervorragend geeignet, um Internationalisierungs- (i18n) Routingmuster zu implementieren. Sie können Präfixmuster verwenden, um mehrere Sprachen zu verwalten und gleichzeitig saubere, SEO-freundliche URLs zu erhalten.
Verwenden Sie optionale Sprachpräfixe, um URLs wie /en/about, /fr/about oder einfach /about (Standardsprache) zu unterstützen
// Route: /{-$locale}/about
export const Route = createFileRoute('/{-$locale}/about')({
component: AboutComponent,
})
function AboutComponent() {
const { locale } = Route.useParams()
const currentLocale = locale || 'en' // Default to English
const content = {
en: { title: 'About Us', description: 'Learn more about our company.' },
fr: {
title: 'À Propos',
description: 'En savoir plus sur notre entreprise.',
},
es: {
title: 'Acerca de',
description: 'Conoce más sobre nuestra empresa.',
},
}
return (
<div>
<h1>{content[currentLocale]?.title}</h1>
<p>{content[currentLocale]?.description}</p>
</div>
)
}
// Route: /{-$locale}/about
export const Route = createFileRoute('/{-$locale}/about')({
component: AboutComponent,
})
function AboutComponent() {
const { locale } = Route.useParams()
const currentLocale = locale || 'en' // Default to English
const content = {
en: { title: 'About Us', description: 'Learn more about our company.' },
fr: {
title: 'À Propos',
description: 'En savoir plus sur notre entreprise.',
},
es: {
title: 'Acerca de',
description: 'Conoce más sobre nuestra empresa.',
},
}
return (
<div>
<h1>{content[currentLocale]?.title}</h1>
<p>{content[currentLocale]?.description}</p>
</div>
)
}
Dieses Muster gleicht Folgendes ab
Kombinieren Sie optionale Parameter für anspruchsvollere i18n-Routen
// Route: /{-$locale}/blog/{-$category}/$slug
export const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({
beforeLoad: async ({ params }) => {
const locale = params.locale || 'en'
const category = params.category
// Validate locale and category
const validLocales = ['en', 'fr', 'es', 'de']
if (locale && !validLocales.includes(locale)) {
throw new Error('Invalid locale')
}
return { locale, category }
},
loader: async ({ params, context }) => {
const { locale } = context
const { slug, category } = params
return fetchBlogPost({ slug, category, locale })
},
component: BlogPostComponent,
})
function BlogPostComponent() {
const { locale, category, slug } = Route.useParams()
const data = Route.useLoaderData()
return (
<article>
<h1>{data.title}</h1>
<p>
Category: {category || 'All'} | Language: {locale || 'en'}
</p>
<div>{data.content}</div>
</article>
)
}
// Route: /{-$locale}/blog/{-$category}/$slug
export const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({
beforeLoad: async ({ params }) => {
const locale = params.locale || 'en'
const category = params.category
// Validate locale and category
const validLocales = ['en', 'fr', 'es', 'de']
if (locale && !validLocales.includes(locale)) {
throw new Error('Invalid locale')
}
return { locale, category }
},
loader: async ({ params, context }) => {
const { locale } = context
const { slug, category } = params
return fetchBlogPost({ slug, category, locale })
},
component: BlogPostComponent,
})
function BlogPostComponent() {
const { locale, category, slug } = Route.useParams()
const data = Route.useLoaderData()
return (
<article>
<h1>{data.title}</h1>
<p>
Category: {category || 'All'} | Language: {locale || 'en'}
</p>
<div>{data.content}</div>
</article>
)
}
Dies unterstützt URLs wie
Erstellen Sie Sprachumschalter mit optionalen i18n-Parametern und Funktionsparametern
function LanguageSwitcher() {
const currentParams = useParams({ strict: false })
const languages = [
{ code: 'en', name: 'English' },
{ code: 'fr', name: 'Français' },
{ code: 'es', name: 'Español' },
]
return (
<div className="language-switcher">
{languages.map(({ code, name }) => (
<Link
key={code}
to="/{-$locale}/blog/{-$category}/$slug"
params={(prev) => ({
...prev,
locale: code === 'en' ? undefined : code, // Remove 'en' for clean URLs
})}
className={currentParams.locale === code ? 'active' : ''}
>
{name}
</Link>
))}
</div>
)
}
function LanguageSwitcher() {
const currentParams = useParams({ strict: false })
const languages = [
{ code: 'en', name: 'English' },
{ code: 'fr', name: 'Français' },
{ code: 'es', name: 'Español' },
]
return (
<div className="language-switcher">
{languages.map(({ code, name }) => (
<Link
key={code}
to="/{-$locale}/blog/{-$category}/$slug"
params={(prev) => ({
...prev,
locale: code === 'en' ? undefined : code, // Remove 'en' for clean URLs
})}
className={currentParams.locale === code ? 'active' : ''}
>
{name}
</Link>
))}
</div>
)
}
Sie können auch ausgefeiltere Logik für die Sprachumschaltung erstellen
function AdvancedLanguageSwitcher() {
const currentParams = useParams({ strict: false })
const handleLanguageChange = (newLocale: string) => {
return (prev: any) => {
// Preserve all existing params but update locale
const updatedParams = { ...prev }
if (newLocale === 'en') {
// Remove locale for clean English URLs
delete updatedParams.locale
} else {
updatedParams.locale = newLocale
}
return updatedParams
}
}
return (
<div className="language-switcher">
<Link
to="/{-$locale}/blog/{-$category}/$slug"
params={handleLanguageChange('fr')}
>
Français
</Link>
<Link
to="/{-$locale}/blog/{-$category}/$slug"
params={handleLanguageChange('es')}
>
Español
</Link>
<Link
to="/{-$locale}/blog/{-$category}/$slug"
params={handleLanguageChange('en')}
>
English
</Link>
</div>
)
}
function AdvancedLanguageSwitcher() {
const currentParams = useParams({ strict: false })
const handleLanguageChange = (newLocale: string) => {
return (prev: any) => {
// Preserve all existing params but update locale
const updatedParams = { ...prev }
if (newLocale === 'en') {
// Remove locale for clean English URLs
delete updatedParams.locale
} else {
updatedParams.locale = newLocale
}
return updatedParams
}
}
return (
<div className="language-switcher">
<Link
to="/{-$locale}/blog/{-$category}/$slug"
params={handleLanguageChange('fr')}
>
Français
</Link>
<Link
to="/{-$locale}/blog/{-$category}/$slug"
params={handleLanguageChange('es')}
>
Español
</Link>
<Link
to="/{-$locale}/blog/{-$category}/$slug"
params={handleLanguageChange('en')}
>
English
</Link>
</div>
)
}
Organisieren Sie i18n-Routen mit optionalen Parametern für flexible Locale-Behandlung
// Route structure:
// routes/
// {-$locale}/
// index.tsx // /, /en, /fr
// about.tsx // /about, /en/about, /fr/about
// blog/
// index.tsx // /blog, /en/blog, /fr/blog
// $slug.tsx // /blog/post, /en/blog/post, /fr/blog/post
// routes/{-$locale}/index.tsx
export const Route = createFileRoute('/{-$locale}/')({
component: HomeComponent,
})
function HomeComponent() {
const { locale } = Route.useParams()
const isRTL = ['ar', 'he', 'fa'].includes(locale || '')
return (
<div dir={isRTL ? 'rtl' : 'ltr'}>
<h1>Welcome ({locale || 'en'})</h1>
{/* Localized content */}
</div>
)
}
// routes/{-$locale}/about.tsx
export const Route = createFileRoute('/{-$locale}/about')({
component: AboutComponent,
})
// Route structure:
// routes/
// {-$locale}/
// index.tsx // /, /en, /fr
// about.tsx // /about, /en/about, /fr/about
// blog/
// index.tsx // /blog, /en/blog, /fr/blog
// $slug.tsx // /blog/post, /en/blog/post, /fr/blog/post
// routes/{-$locale}/index.tsx
export const Route = createFileRoute('/{-$locale}/')({
component: HomeComponent,
})
function HomeComponent() {
const { locale } = Route.useParams()
const isRTL = ['ar', 'he', 'fa'].includes(locale || '')
return (
<div dir={isRTL ? 'rtl' : 'ltr'}>
<h1>Welcome ({locale || 'en'})</h1>
{/* Localized content */}
</div>
)
}
// routes/{-$locale}/about.tsx
export const Route = createFileRoute('/{-$locale}/about')({
component: AboutComponent,
})
Behandeln Sie SEO für i18n-Routen korrekt
export const Route = createFileRoute('/{-$locale}/products/$id')({
component: ProductComponent,
head: ({ params, loaderData }) => {
const locale = params.locale || 'en'
const product = loaderData
return {
title: product.title[locale] || product.title.en,
meta: [
{
name: 'description',
content: product.description[locale] || product.description.en,
},
{
property: 'og:locale',
content: locale,
},
],
links: [
// Canonical URL (always use default locale format)
{
rel: 'canonical',
href: `https://example.com/products/${params.id}`,
},
// Alternate language versions
{
rel: 'alternate',
hreflang: 'en',
href: `https://example.com/products/${params.id}`,
},
{
rel: 'alternate',
hreflang: 'fr',
href: `https://example.com/fr/products/${params.id}`,
},
{
rel: 'alternate',
hreflang: 'es',
href: `https://example.com/es/products/${params.id}`,
},
],
}
},
})
export const Route = createFileRoute('/{-$locale}/products/$id')({
component: ProductComponent,
head: ({ params, loaderData }) => {
const locale = params.locale || 'en'
const product = loaderData
return {
title: product.title[locale] || product.title.en,
meta: [
{
name: 'description',
content: product.description[locale] || product.description.en,
},
{
property: 'og:locale',
content: locale,
},
],
links: [
// Canonical URL (always use default locale format)
{
rel: 'canonical',
href: `https://example.com/products/${params.id}`,
},
// Alternate language versions
{
rel: 'alternate',
hreflang: 'en',
href: `https://example.com/products/${params.id}`,
},
{
rel: 'alternate',
hreflang: 'fr',
href: `https://example.com/fr/products/${params.id}`,
},
{
rel: 'alternate',
hreflang: 'es',
href: `https://example.com/es/products/${params.id}`,
},
],
}
},
})
Stellen Sie die Typsicherheit für Ihre i18n-Implementierungen sicher
// Define supported locales
type Locale = 'en' | 'fr' | 'es' | 'de'
// Type-safe locale validation
function validateLocale(locale: string | undefined): locale is Locale {
return ['en', 'fr', 'es', 'de'].includes(locale as Locale)
}
export const Route = createFileRoute('/{-$locale}/shop/{-$category}')({
beforeLoad: async ({ params }) => {
const { locale } = params
// Type-safe locale validation
if (locale && !validateLocale(locale)) {
throw redirect({
to: '/shop/{-$category}',
params: { category: params.category },
})
}
return {
locale: (locale as Locale) || 'en',
isDefaultLocale: !locale || locale === 'en',
}
},
component: ShopComponent,
})
function ShopComponent() {
const { locale, category } = Route.useParams()
const { isDefaultLocale } = Route.useRouteContext()
// TypeScript knows locale is Locale | undefined
// and we have validated it in beforeLoad
return (
<div>
<h1>Shop {category ? `- ${category}` : ''}</h1>
<p>Language: {locale || 'en'}</p>
{!isDefaultLocale && (
<Link to="/shop/{-$category}" params={{ category }}>
View in English
</Link>
)}
</div>
)
}
// Define supported locales
type Locale = 'en' | 'fr' | 'es' | 'de'
// Type-safe locale validation
function validateLocale(locale: string | undefined): locale is Locale {
return ['en', 'fr', 'es', 'de'].includes(locale as Locale)
}
export const Route = createFileRoute('/{-$locale}/shop/{-$category}')({
beforeLoad: async ({ params }) => {
const { locale } = params
// Type-safe locale validation
if (locale && !validateLocale(locale)) {
throw redirect({
to: '/shop/{-$category}',
params: { category: params.category },
})
}
return {
locale: (locale as Locale) || 'en',
isDefaultLocale: !locale || locale === 'en',
}
},
component: ShopComponent,
})
function ShopComponent() {
const { locale, category } = Route.useParams()
const { isDefaultLocale } = Route.useRouteContext()
// TypeScript knows locale is Locale | undefined
// and we have validated it in beforeLoad
return (
<div>
<h1>Shop {category ? `- ${category}` : ''}</h1>
<p>Language: {locale || 'en'}</p>
{!isDefaultLocale && (
<Link to="/shop/{-$category}" params={{ category }}>
View in English
</Link>
)}
</div>
)
}
Optionale Pfadparameter bieten eine leistungsstarke und flexible Grundlage für die Implementierung von Internationalisierung in Ihren TanStack Router-Anwendungen. Ob Sie präfixbasierte oder kombinierte Ansätze bevorzugen, Sie können saubere, SEO-freundliche URLs erstellen und gleichzeitig eine ausgezeichnete Entwicklererfahrung und Typsicherheit beibehalten.
Standardmäßig werden Pfadparameter mit encodeURIComponent kodiert. Wenn Sie andere gültige URI-Zeichen (z. B. @ oder +) zulassen möchten, können Sie dies in Ihren RouterOptions angeben.
Beispielanwendung
const router = createRouter({
// ...
pathParamsAllowedCharacters: ['@'],
})
const router = createRouter({
// ...
pathParamsAllowedCharacters: ['@'],
})
Die folgende Liste enthält die akzeptierten erlaubten Zeichen
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.