URLSearchParams verwenden?<Link search />useNavigate(), navigate({ search })router.navigate({ search })<Navigate search />Ähnlich wie TanStack Query die Handhabung von Server-State in Ihren React- und Solid-Anwendungen vereinfacht hat, zielt TanStack Router darauf ab, die Leistung von URL-Suchparametern in Ihren Anwendungen zu erschließen.
🧠 Wenn Sie einen sehr alten Browser wie IE11 verwenden, benötigen Sie möglicherweise ein Polyfill für URLSearchParams.
Wir verstehen es, Sie hören in letzter Zeit viel "nutzen Sie die Plattform" und größtenteils stimmen wir zu. Wir glauben jedoch auch, dass es wichtig ist, zu erkennen, wo die Plattform für fortgeschrittenere Anwendungsfälle zu kurz greift, und wir glauben, dass URLSearchParams eine dieser Umstände ist.
Traditionelle Suchparameter-APIs gehen normalerweise von einigen Annahmen aus
Die Realität unterscheidet sich jedoch stark von diesen Annahmen.
Sie haben wahrscheinlich Suchparameter wie ?page=3 oder ?filter-name=tanner in der URL gesehen. Es besteht kein Zweifel, dass dies wirklich eine Form des globalen Zustands ist, der sich in der URL befindet. Es ist wertvoll, bestimmte Zustände in der URL zu speichern, weil
Um dies zu erreichen, ist der erste Schritt in TanStack Router ein leistungsstarker Suchparameter-Parser, der die Suchzeichenkette Ihrer URL automatisch in strukturiertes JSON umwandelt. Das bedeutet, dass Sie jede JSON-serialisierbare Datenstruktur in Ihren Suchparametern speichern können und sie wird als JSON geparst und serialisiert. Dies ist eine enorme Verbesserung gegenüber URLSearchParams, das nur begrenzte Unterstützung für arrayähnliche Strukturen und verschachtelte Daten bietet.
Zum Beispiel die Navigation zur folgenden Route
const link = (
<Link
to="/shop"
search={{
pageIndex: 3,
includeCategories: ['electronics', 'gifts'],
sortBy: 'price',
desc: true,
}}
/>
)
const link = (
<Link
to="/shop"
search={{
pageIndex: 3,
includeCategories: ['electronics', 'gifts'],
sortBy: 'price',
desc: true,
}}
/>
)
führt zur folgenden URL
/shop?pageIndex=3&includeCategories=%5B%22electronics%22%2C%22gifts%22%5D&sortBy=price&desc=true
/shop?pageIndex=3&includeCategories=%5B%22electronics%22%2C%22gifts%22%5D&sortBy=price&desc=true
Wenn diese URL geparst wird, werden die Suchparameter korrekt in das folgende JSON konvertiert
{
"pageIndex": 3,
"includeCategories": ["electronics", "gifts"],
"sortBy": "price",
"desc": true
}
{
"pageIndex": 3,
"includeCategories": ["electronics", "gifts"],
"sortBy": "price",
"desc": true
}
Wenn Sie bemerkt haben, gibt es hier ein paar Dinge, die passieren
🧠 Es ist üblich, dass andere Tools davon ausgehen, dass Suchparameter immer flach und zeichenkettenbasiert sind. Deshalb haben wir uns entschieden, die Dinge auf der ersten Ebene URLSearchParam-konform zu halten. Dies bedeutet letztendlich, dass TanStack Router Ihre verschachtelten Suchparameter zwar als JSON verwaltet, andere Tools jedoch weiterhin normal in die URL schreiben und Parameter der ersten Ebene lesen können.
Obwohl TanStack Router Suchparameter in zuverlässiges JSON parsen kann, stammen sie letztendlich von einem für den Benutzer sichtbaren Rohtext-Input. Ähnlich wie bei anderen Serialisierungsgrenzen bedeutet dies, dass sie, bevor Sie Suchparameter verwenden, in ein Format validiert werden sollten, dem Ihre Anwendung vertrauen und auf das sie sich verlassen kann.
TanStack Router bietet praktische APIs zum Validieren und Typisieren von Suchparametern. Dies beginnt alles mit der validateSearch Option der Route
// /routes/shop.products.tsx
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price'
type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}
export const Route = createFileRoute('/shop/products')({
validateSearch: (search: Record<string, unknown>): ProductSearch => {
// validate and parse the search params into a typed state
return {
page: Number(search?.page ?? 1),
filter: (search.filter as string) || '',
sort: (search.sort as ProductSearchSortOptions) || 'newest',
}
},
})
// /routes/shop.products.tsx
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price'
type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}
export const Route = createFileRoute('/shop/products')({
validateSearch: (search: Record<string, unknown>): ProductSearch => {
// validate and parse the search params into a typed state
return {
page: Number(search?.page ?? 1),
filter: (search.filter as string) || '',
sort: (search.sort as ProductSearchSortOptions) || 'newest',
}
},
})
Im obigen Beispiel validieren wir die Suchparameter der Route und geben ein typisiertes ProductSearch-Objekt zurück. Dieses typisierte Objekt steht dann anderen Optionen dieser Route und auch allen untergeordneten Routen zur Verfügung!
Die Option validateSearch ist eine Funktion, die die JSON-geparsten (aber nicht validierten) Suchparameter als Record<string, unknown> erhält und ein typisiertes Objekt Ihrer Wahl zurückgibt. Es ist am besten, sinnvolle Fallbacks für fehlerhafte oder unerwartete Suchparameter bereitzustellen, damit die Benutzererfahrung nicht unterbrochen wird.
Hier ist ein Beispiel
// /routes/shop.products.tsx
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price'
type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}
export const Route = createFileRoute('/shop/products')({
validateSearch: (search: Record<string, unknown>): ProductSearch => {
// validate and parse the search params into a typed state
return {
page: Number(search?.page ?? 1),
filter: (search.filter as string) || '',
sort: (search.sort as ProductSearchSortOptions) || 'newest',
}
},
})
// /routes/shop.products.tsx
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price'
type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}
export const Route = createFileRoute('/shop/products')({
validateSearch: (search: Record<string, unknown>): ProductSearch => {
// validate and parse the search params into a typed state
return {
page: Number(search?.page ?? 1),
filter: (search.filter as string) || '',
sort: (search.sort as ProductSearchSortOptions) || 'newest',
}
},
})
Hier ist ein Beispiel, das die Bibliothek Zod verwendet (aber Sie können jede beliebige Validierungsbibliothek verwenden), um die Suchparameter in einem Schritt sowohl zu validieren als auch zu typisieren
// /routes/shop.products.tsx
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().catch(1),
filter: z.string().catch(''),
sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),
})
type ProductSearch = z.infer<typeof productSearchSchema>
export const Route = createFileRoute('/shop/products')({
validateSearch: (search) => productSearchSchema.parse(search),
})
// /routes/shop.products.tsx
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().catch(1),
filter: z.string().catch(''),
sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),
})
type ProductSearch = z.infer<typeof productSearchSchema>
export const Route = createFileRoute('/shop/products')({
validateSearch: (search) => productSearchSchema.parse(search),
})
Da validateSearch auch ein Objekt mit der Eigenschaft parse akzeptiert, kann dies verkürzt werden zu
validateSearch: productSearchSchema
validateSearch: productSearchSchema
Im obigen Beispiel haben wir den Modifikator .catch() von Zod anstelle von .default() verwendet, um dem Benutzer keinen Fehler anzuzeigen, da wir fest davon überzeugt sind, dass bei fehlerhaften Suchparametern Sie die Benutzererfahrung in der App nicht durch eine große Fehlermeldung unterbrechen möchten. Dennoch kann es Zeiten geben, in denen Sie eine Fehlermeldung anzeigen möchten. In diesem Fall können Sie .default() anstelle von .catch() verwenden.
Die zugrunde liegende Mechanik, warum dies funktioniert, beruht darauf, dass die Funktion validateSearch einen Fehler auslöst. Wenn ein Fehler ausgelöst wird, wird die Option onError der Route ausgelöst (und error.routerCode wird auf VALIDATE_SEARCH gesetzt) und die errorComponent wird anstelle der component der Route gerendert, wo Sie den Suchparameterfehler nach Belieben behandeln können.
Bei der Verwendung einer Bibliothek wie Zod zur Validierung von Suchparametern möchten Sie möglicherweise Suchparameter transformieren, bevor Sie die Suchparameter in die URL übernehmen. Eine übliche zod transform ist z. B. default.
import { createFileRoute } from '@tanstack/solid-router'
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().default(1),
filter: z.string().default(''),
sort: z.enum(['newest', 'oldest', 'price']).default('newest'),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
import { createFileRoute } from '@tanstack/solid-router'
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().default(1),
filter: z.string().default(''),
sort: z.enum(['newest', 'oldest', 'price']).default('newest'),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
Es mag überraschen, dass bei der Navigation zu dieser Route search erforderlich ist. Der folgende Link wird mit einem Typfehler als fehlend search markiert.
<Link to="/shop/products" />
<Link to="/shop/products" />
Für Validierungsbibliotheken empfehlen wir die Verwendung von Adaptern, die die korrekten input- und output-Typen ableiten.
Ein Adapter wird für Zod bereitgestellt, der die korrekten input- und output-Typen durchleitet
import { createFileRoute } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().default(1),
filter: z.string().default(''),
sort: z.enum(['newest', 'oldest', 'price']).default('newest'),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: zodValidator(productSearchSchema),
})
import { createFileRoute } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().default(1),
filter: z.string().default(''),
sort: z.enum(['newest', 'oldest', 'price']).default('newest'),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: zodValidator(productSearchSchema),
})
Der wichtige Teil hier ist die folgende Verwendung von Link, die keine search-Parameter mehr benötigt
<Link to="/shop/products" />
<Link to="/shop/products" />
Die Verwendung von catch hier überschreibt jedoch die Typen und macht page, filter und sort zu unknown, was zu Typverlust führt. Wir haben diesen Fall behandelt, indem wir eine generische Funktion fallback bereitgestellt haben, die die Typen beibehält, aber einen fallback-Wert liefert, wenn die Validierung fehlschlägt
import { createFileRoute } from '@tanstack/solid-router'
import { fallback, zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
page: fallback(z.number(), 1).default(1),
filter: fallback(z.string(), '').default(''),
sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
'newest',
),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: zodValidator(productSearchSchema),
})
import { createFileRoute } from '@tanstack/solid-router'
import { fallback, zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
page: fallback(z.number(), 1).default(1),
filter: fallback(z.string(), '').default(''),
sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
'newest',
),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: zodValidator(productSearchSchema),
})
Daher ist bei der Navigation zu dieser Route search optional und behält die korrekten Typen bei.
Obwohl nicht empfohlen, ist es auch möglich, input und output-Typen zu konfigurieren, falls der output-Typ genauer ist als der input-Typ
const productSearchSchema = z.object({
page: fallback(z.number(), 1).default(1),
filter: fallback(z.string(), '').default(''),
sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
'newest',
),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: zodValidator({
schema: productSearchSchema,
input: 'output',
output: 'input',
}),
})
const productSearchSchema = z.object({
page: fallback(z.number(), 1).default(1),
filter: fallback(z.string(), '').default(''),
sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
'newest',
),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: zodValidator({
schema: productSearchSchema,
input: 'output',
output: 'input',
}),
})
Dies bietet Flexibilität bei der Wahl des Typs, den Sie für die Navigation und die Typen, die Sie für das Lesen von Suchparametern inferieren möchten.
Warnung
Router erwartet, dass das Valibot 1.0-Paket installiert ist.
Bei der Verwendung von Valibot ist kein Adapter erforderlich, um sicherzustellen, dass die korrekten input- und output-Typen für die Navigation und das Lesen von Suchparametern verwendet werden. Dies liegt daran, dass Valibot Standard Schema implementiert.
import { createFileRoute } from '@tanstack/solid-router'
import * as v from 'valibot'
const productSearchSchema = v.object({
page: v.optional(v.fallback(v.number(), 1), 1),
filter: v.optional(v.fallback(v.string(), ''), ''),
sort: v.optional(
v.fallback(v.picklist(['newest', 'oldest', 'price']), 'newest'),
'newest',
),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
import { createFileRoute } from '@tanstack/solid-router'
import * as v from 'valibot'
const productSearchSchema = v.object({
page: v.optional(v.fallback(v.number(), 1), 1),
filter: v.optional(v.fallback(v.string(), ''), ''),
sort: v.optional(
v.fallback(v.picklist(['newest', 'oldest', 'price']), 'newest'),
'newest',
),
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
Warnung
Router erwartet, dass das Arktype 2.0-rc-Paket installiert ist.
Bei der Verwendung von ArkType ist kein Adapter erforderlich, um sicherzustellen, dass die korrekten input- und output-Typen für die Navigation und das Lesen von Suchparametern verwendet werden. Dies liegt daran, dass ArkType Standard Schema implementiert.
import { createFileRoute } from '@tanstack/solid-router'
import { type } from 'arktype'
const productSearchSchema = type({
page: 'number = 1',
filter: 'string = ""',
sort: '"newest" | "oldest" | "price" = "newest"',
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
import { createFileRoute } from '@tanstack/solid-router'
import { type } from 'arktype'
const productSearchSchema = type({
page: 'number = 1',
filter: 'string = ""',
sort: '"newest" | "oldest" | "price" = "newest"',
})
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
Bei der Verwendung von Effect/Schema ist kein Adapter erforderlich, um sicherzustellen, dass die korrekten input- und output-Typen für die Navigation und das Lesen von Suchparametern verwendet werden. Dies liegt daran, dass Effect/Schema Standard Schema implementiert.
import { createFileRoute } from '@tanstack/solid-router'
import { Schema as S } from 'effect'
const productSearchSchema = S.standardSchemaV1(
S.Struct({
page: S.NumberFromString.pipe(
S.optional,
S.withDefaults({
constructor: () => 1,
decoding: () => 1,
}),
),
filter: S.String.pipe(
S.optional,
S.withDefaults({
constructor: () => '',
decoding: () => '',
}),
),
sort: S.Literal('newest', 'oldest', 'price').pipe(
S.optional,
S.withDefaults({
constructor: () => 'newest' as const,
decoding: () => 'newest' as const,
}),
),
}),
)
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
import { createFileRoute } from '@tanstack/solid-router'
import { Schema as S } from 'effect'
const productSearchSchema = S.standardSchemaV1(
S.Struct({
page: S.NumberFromString.pipe(
S.optional,
S.withDefaults({
constructor: () => 1,
decoding: () => 1,
}),
),
filter: S.String.pipe(
S.optional,
S.withDefaults({
constructor: () => '',
decoding: () => '',
}),
),
sort: S.Literal('newest', 'oldest', 'price').pipe(
S.optional,
S.withDefaults({
constructor: () => 'newest' as const,
decoding: () => 'newest' as const,
}),
),
}),
)
export const Route = createFileRoute('/shop/products/')({
validateSearch: productSearchSchema,
})
Sobald Ihre Suchparameter validiert und typisiert wurden, sind Sie endlich bereit, mit dem Lesen und Schreiben zu beginnen. Es gibt mehrere Möglichkeiten, dies in TanStack Router zu tun. Schauen wir uns diese an.
Bitte lesen Sie den Abschnitt Suchparameter in Loadern, um weitere Informationen darüber zu erhalten, wie Sie Suchparameter in Loadern mit der Option loaderDeps lesen.
Die Suchparameter und Typen von Eltern werden beim Abstieg im Routenbaum zusammengeführt, sodass untergeordnete Routen auch Zugriff auf die Suchparameter ihrer Eltern haben.
const productSearchSchema = z.object({
page: z.number().catch(1),
filter: z.string().catch(''),
sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),
})
type ProductSearch = z.infer<typeof productSearchSchema>
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
})
const productSearchSchema = z.object({
page: z.number().catch(1),
filter: z.string().catch(''),
sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),
})
type ProductSearch = z.infer<typeof productSearchSchema>
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
})
export const Route = createFileRoute('/shop/products/$productId')({
beforeLoad: ({ search }) => {
search
// ^? ProductSearch ✅
},
})
export const Route = createFileRoute('/shop/products/$productId')({
beforeLoad: ({ search }) => {
search
// ^? ProductSearch ✅
},
})
Sie können auf die validierten Suchparameter Ihrer Route in der component Ihrer Route über den Hook useSearch zugreifen.
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
})
const ProductList = () => {
const { page, filter, sort } = Route.useSearch()
return <div>...</div>
}
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
})
const ProductList = () => {
const { page, filter, sort } = Route.useSearch()
return <div>...</div>
}
Tipp
Wenn Ihre Komponente Code-Split ist, können Sie die Funktion getRouteApi verwenden, um den Import der Route-Konfiguration zu vermeiden und Zugriff auf den typisierten Hook useSearch() zu erhalten.
Sie können auf die validierten Suchparameter Ihrer Route an beliebiger Stelle in Ihrer App über den Hook useSearch zugreifen. Durch Übergabe der from-ID/Pfads Ihrer Ursprungsroute erhalten Sie eine noch bessere Typsicherheit.
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
// ...
})
// Somewhere else...
// /components/product-list-sidebar.tsx
const routeApi = getRouteApi('/shop/products')
const ProductList = () => {
const routeSearch = routeApi.useSearch()
// OR
const { page, filter, sort } = useSearch({
from: Route.fullPath,
})
return <div>...</div>
}
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
// ...
})
// Somewhere else...
// /components/product-list-sidebar.tsx
const routeApi = getRouteApi('/shop/products')
const ProductList = () => {
const routeSearch = routeApi.useSearch()
// OR
const { page, filter, sort } = useSearch({
from: Route.fullPath,
})
return <div>...</div>
}
Oder Sie können die Typsicherheit lockern und ein optionales search-Objekt erhalten, indem Sie strict: false übergeben.
function ProductList() {
const search = useSearch({
strict: false,
})
// {
// page: number | undefined
// filter: string | undefined
// sort: 'newest' | 'oldest' | 'price' | undefined
// }
return <div>...</div>
}
function ProductList() {
const search = useSearch({
strict: false,
})
// {
// page: number | undefined
// filter: string | undefined
// sort: 'newest' | 'oldest' | 'price' | undefined
// }
return <div>...</div>
}
Nachdem Sie nun gelernt haben, wie Sie die Suchparameter Ihrer Route lesen, werden Sie sich freuen zu wissen, dass Sie bereits die primären APIs zum Ändern und Aktualisieren gesehen haben. Lassen Sie uns uns kurz erinnern.
Der beste Weg, Suchparameter zu aktualisieren, ist die Verwendung der Prop search der Komponente <Link />.
Wenn der Suchparameter für die aktuelle Seite aktualisiert werden soll und die Prop from angegeben ist, kann die Prop to weggelassen werden.
Hier ist ein Beispiel
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
})
const ProductList = () => {
return (
<div>
<Link from={Route.fullPath} search={(prev) => ({ page: prev.page + 1 })}>
Next Page
</Link>
</div>
)
}
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products')({
validateSearch: productSearchSchema,
})
const ProductList = () => {
return (
<div>
<Link from={Route.fullPath} search={(prev) => ({ page: prev.page + 1 })}>
Next Page
</Link>
</div>
)
}
Wenn Sie die Suchparameter in einer generischen Komponente aktualisieren möchten, die auf mehreren Routen gerendert wird, kann die Angabe von from schwierig sein.
In diesem Szenario können Sie to="." setzen, was Ihnen Zugriff auf lose typisierte Suchparameter gewährt.
Hier ist ein Beispiel, das dies veranschaulicht
// `page` is a search param that is defined in the __root route and hence available on all routes.
const PageSelector = () => {
return (
<div>
<Link to="." search={(prev) => ({ ...prev, page: prev.page + 1 })}>
Next Page
</Link>
</div>
)
}
// `page` is a search param that is defined in the __root route and hence available on all routes.
const PageSelector = () => {
return (
<div>
<Link to="." search={(prev) => ({ ...prev, page: prev.page + 1 })}>
Next Page
</Link>
</div>
)
}
Wenn die generische Komponente nur in einem bestimmten Unterbaum des Routenbaums gerendert wird, können Sie diesen Unterbaum mit from angeben. Hier können Sie to='.' weglassen, wenn Sie möchten.
// `page` is a search param that is defined in the /posts route and hence available on all of its child routes.
const PageSelector = () => {
return (
<div>
<Link
from="/posts"
to="."
search={(prev) => ({ ...prev, page: prev.page + 1 })}
>
Next Page
</Link>
</div>
)
// `page` is a search param that is defined in the /posts route and hence available on all of its child routes.
const PageSelector = () => {
return (
<div>
<Link
from="/posts"
to="."
search={(prev) => ({ ...prev, page: prev.page + 1 })}
>
Next Page
</Link>
</div>
)
Die Funktion navigate akzeptiert auch eine Option search, die genauso funktioniert wie die Prop search auf <Link />.
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products/$productId')({
validateSearch: productSearchSchema,
})
const ProductList = () => {
const navigate = useNavigate({ from: Route.fullPath })
return (
<div>
<button
onClick={() => {
navigate({
search: (prev) => ({ page: prev.page + 1 }),
})
}}
>
Next Page
</button>
</div>
)
}
// /routes/shop.products.tsx
export const Route = createFileRoute('/shop/products/$productId')({
validateSearch: productSearchSchema,
})
const ProductList = () => {
const navigate = useNavigate({ from: Route.fullPath })
return (
<div>
<button
onClick={() => {
navigate({
search: (prev) => ({ page: prev.page + 1 }),
})
}}
>
Next Page
</button>
</div>
)
}
Die Funktion router.navigate funktioniert genauso wie der obige Hook/Funktion useNavigate/navigate.
Die Komponente <Navigate search /> funktioniert genauso wie der obige Hook/Funktion useNavigate/navigate, akzeptiert aber seine Optionen als Props anstelle eines Funktionsarguments.
Wenn Link-hrefs erstellt werden, ist standardmäßig nur die search-Eigenschaft eines <Link> für den Abfragezeichenfolgen-Teil relevant.
TanStack Router bietet eine Möglichkeit, Suchparameter zu manipulieren, bevor der href generiert wird, über Such-Middlewares. Such-Middlewares sind Funktionen, die die Suchparameter transformieren, wenn neue Links für eine Route oder ihre Nachfolger generiert werden. Sie werden auch bei der Navigation nach der Suchvalidierung ausgeführt, um die Manipulation der Abfragezeichenfolge zu ermöglichen.
Das folgende Beispiel zeigt, wie sichergestellt wird, dass für jeden Link, der erstellt wird, der Suchparameter rootValue hinzugefügt wird, falls er Teil der aktuellen Suchparameter ist. Wenn ein Link rootValue innerhalb von search angibt, wird dieser Wert für die Erstellung des Links verwendet.
import { z } from 'zod'
import { createFileRoute } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
rootValue: z.string().optional(),
})
export const Route = createRootRoute({
validateSearch: zodValidator(searchSchema),
search: {
middlewares: [
({ search, next }) => {
const result = next(search)
return {
rootValue: search.rootValue,
...result,
}
},
],
},
})
import { z } from 'zod'
import { createFileRoute } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
rootValue: z.string().optional(),
})
export const Route = createRootRoute({
validateSearch: zodValidator(searchSchema),
search: {
middlewares: [
({ search, next }) => {
const result = next(search)
return {
rootValue: search.rootValue,
...result,
}
},
],
},
})
Da dieser spezielle Anwendungsfall ziemlich häufig vorkommt, bietet TanStack Router eine generische Implementierung, um Suchparameter über retainSearchParams beizubehalten.
import { z } from 'zod'
import { createFileRoute, retainSearchParams } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
rootValue: z.string().optional(),
})
export const Route = createRootRoute({
validateSearch: zodValidator(searchSchema),
search: {
middlewares: [retainSearchParams(['rootValue'])],
},
})
import { z } from 'zod'
import { createFileRoute, retainSearchParams } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
rootValue: z.string().optional(),
})
export const Route = createRootRoute({
validateSearch: zodValidator(searchSchema),
search: {
middlewares: [retainSearchParams(['rootValue'])],
},
})
Ein weiterer gängiger Anwendungsfall ist das Entfernen von Suchparametern aus Links, wenn deren Standardwert festgelegt ist. TanStack Router bietet eine generische Implementierung für diesen Anwendungsfall über stripSearchParams.
import { z } from 'zod'
import { createFileRoute, stripSearchParams } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
const defaultValues = {
one: 'abc',
two: 'xyz',
}
const searchSchema = z.object({
one: z.string().default(defaultValues.one),
two: z.string().default(defaultValues.two),
})
export const Route = createFileRoute('/hello')({
validateSearch: zodValidator(searchSchema),
search: {
// strip default values
middlewares: [stripSearchParams(defaultValues)],
},
})
import { z } from 'zod'
import { createFileRoute, stripSearchParams } from '@tanstack/solid-router'
import { zodValidator } from '@tanstack/zod-adapter'
const defaultValues = {
one: 'abc',
two: 'xyz',
}
const searchSchema = z.object({
one: z.string().default(defaultValues.one),
two: z.string().default(defaultValues.two),
})
export const Route = createFileRoute('/hello')({
validateSearch: zodValidator(searchSchema),
search: {
// strip default values
middlewares: [stripSearchParams(defaultValues)],
},
})
Mehrere Middlewares können verkettet werden. Das folgende Beispiel zeigt, wie sowohl retainSearchParams als auch stripSearchParams kombiniert werden.
import {
Link,
createFileRoute,
retainSearchParams,
stripSearchParams,
} from '@tanstack/solid-router'
import { z } from 'zod'
import { zodValidator } from '@tanstack/zod-adapter'
const defaultValues = ['foo', 'bar']
export const Route = createFileRoute('/search')({
validateSearch: zodValidator(
z.object({
retainMe: z.string().optional(),
arrayWithDefaults: z.string().array().default(defaultValues),
required: z.string(),
}),
),
search: {
middlewares: [
retainSearchParams(['retainMe']),
stripSearchParams({ arrayWithDefaults: defaultValues }),
],
},
})
import {
Link,
createFileRoute,
retainSearchParams,
stripSearchParams,
} from '@tanstack/solid-router'
import { z } from 'zod'
import { zodValidator } from '@tanstack/zod-adapter'
const defaultValues = ['foo', 'bar']
export const Route = createFileRoute('/search')({
validateSearch: zodValidator(
z.object({
retainMe: z.string().optional(),
arrayWithDefaults: z.string().array().default(defaultValues),
required: z.string(),
}),
),
search: {
middlewares: [
retainSearchParams(['retainMe']),
stripSearchParams({ arrayWithDefaults: defaultValues }),
],
},
})
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.