URLSearchParams verwenden?<Link search />useNavigate(), navigate({ search })router.navigate({ search })<Navigate search />Ähnlich wie TanStack Query die Handhabung von Serverzuständen in Ihren React- und Solid-Anwendungen vereinfacht hat, zielt TanStack Router darauf ab, die Leistung von URL-Suchparametern in Ihren Anwendungen freizusetzen.
🧠 Wenn Sie einen sehr alten Browser wie IE11 verwenden, müssen Sie möglicherweise einen Polyfill für URLSearchParams verwenden.
Wir verstehen es, Sie haben in letzter Zeit viel "nutzen Sie die Plattform" gehört, und meistens stimmen wir zu. Wir glauben jedoch auch, dass es wichtig ist, zu erkennen, wo die Plattform für fortgeschrittenere Anwendungsfälle hinter den Erwartungen zurückbleibt, und wir glauben, dass URLSearchParams einer dieser Fälle 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 tatsächlich **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 das oben Genannte 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
Beim Parsen dieser URL werden die Suchparameter korrekt in das folgende JSON umgewandelt
{
"pageIndex": 3,
"includeCategories": ["electronics", "gifts"],
"sortBy": "price",
"desc": true
}
{
"pageIndex": 3,
"includeCategories": ["electronics", "gifts"],
"sortBy": "price",
"desc": true
}
Wenn Sie es bemerkt haben, passieren hier ein paar Dinge
🧠 Es ist üblich, dass andere Tools davon ausgehen, dass Suchparameter immer flach und zeichenkettenbasiert sind, weshalb wir uns entschieden haben, auf der ersten Ebene URLSearchParam-konform zu bleiben. Das bedeutet letztendlich, dass TanStack Router Ihre verschachtelten Suchparameter zwar als JSON verwaltet, aber andere Tools immer noch in der Lage sein werden, in die URL zu schreiben und Parameter der ersten Ebene normal zu lesen.
Obwohl TanStack Router Suchparameter in zuverlässiges JSON parsen kann, stammen sie letztendlich von **einem benutzerorientierten Rohtext-Eingabefeld**. Ähnlich wie bei anderen Serialisierungsgrenzen bedeutet dies, dass sie vor der Verwendung durch die Anwendung validiert werden sollten, um ein Format zu erhalten, dem Ihre Anwendung vertrauen und auf das sie sich verlassen kann.
TanStack Router bietet praktische APIs zum Validieren und Typisieren von Suchparametern. All dies beginnt 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 normalerweise am besten, sinnvolle Fallbacks für fehlerhafte oder unerwartete Suchparameter bereitzustellen, damit die Benutzererfahrung ununterbrochen bleibt.
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 Zod-Bibliothek verwendet (aber Sie können jede beliebige Validierungsbibliothek verwenden), um die Suchparameter in einem Schritt zu validieren und 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 .catch()-Modifikator von Zod anstelle von .default() verwendet, um dem Benutzer keinen Fehler anzuzeigen, da wir fest davon überzeugt sind, dass Sie bei fehlerhaften Suchparametern die Benutzererfahrung 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 anstelle von .catch() .default() 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 beliebig 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 an die URL übergeben. Eine übliche zod- transform ist zum Beispiel default.
import { createFileRoute } from '@tanstack/react-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/react-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 überraschend sein, dass bei der Navigation zu dieser Route search erforderlich ist. Der folgende Link wird einen Typfehler melden, da search fehlt.
<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 den korrekten input- und output-Typ durchleitet
import { createFileRoute } from '@tanstack/react-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/react-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, dass die folgende Verwendung von Link search-Parameter nicht 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/react-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/react-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),
})
Wenn Sie also zu dieser Route navigieren, ist 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 ableiten möchten.
Warnung
Router erwartet, dass das Valibot 1.0-Paket installiert ist.
Bei Verwendung von Valibot ist kein Adapter erforderlich, um sicherzustellen, dass die korrekten input- und output-Typen für Navigation und das Lesen von Suchparametern verwendet werden. Dies liegt daran, dass valibot Standard Schema implementiert.
import { createFileRoute } from '@tanstack/react-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/react-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 Verwendung von ArkType ist kein Adapter erforderlich, um sicherzustellen, dass die korrekten input- und output-Typen für Navigation und das Lesen von Suchparametern verwendet werden. Dies liegt daran, dass ArkType Standard Schema implementiert.
import { createFileRoute } from '@tanstack/react-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/react-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 Verwendung von Effect/Schema ist kein Adapter erforderlich, um sicherzustellen, dass die korrekten input- und output-Typen für Navigation und das Lesen von Suchparametern verwendet werden. Dies liegt daran, dass Effect/Schema Standard Schema implementiert.
import { createFileRoute } from '@tanstack/react-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/react-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 sind, sind Sie endlich bereit, mit dem Lesen und Schreiben zu beginnen. In TanStack Router gibt es dafür mehrere Möglichkeiten, lassen Sie uns diese untersuchen.
Bitte lesen Sie den Abschnitt Suchparameter in Loadern für weitere Informationen darüber, wie Suchparameter in Loadern mit der Option loaderDeps gelesen werden.
Die Suchparameter und Typen der 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-splitting-fähig ist, können Sie die getRouteApi-Funktion verwenden, um den Import der Route-Konfiguration zu vermeiden und Zugriff auf den typisierten useSearch()-Hook zu erhalten.
Sie können auf die validierten Suchparameter Ihrer Route überall in Ihrer App mit dem Hook useSearch zugreifen. Durch die Übergabe der ID/des Pfads from 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>
}
Alternativ können Sie 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 erfreut sein zu erfahren, dass Sie bereits die primären APIs zum Ändern und Aktualisieren gesehen haben. Lassen Sie uns uns kurz daran erinnern.
Der beste Weg, Suchparameter zu aktualisieren, ist die Verwendung der search-Eigenschaft der <Link />-Komponente.
Wenn die Suche für die aktuelle Seite aktualisiert werden soll und die from-Eigenschaft angegeben ist, kann die to-Eigenschaft 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 search-Option, die genauso funktioniert wie die search-Eigenschaft 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/die Hook/Funktion useNavigate/navigate.
Die Komponente <Navigate search /> funktioniert genauso wie der obige Hook/die Hook/Funktion useNavigate/navigate, akzeptiert aber ihre Optionen als Props anstelle eines Funktionsarguments.
Beim Erstellen von Link-hrefs ist standardmäßig nur die search-Eigenschaft eines <Link> für den Abfragezeichenketten-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 beim Generieren neuer Links für eine Route oder deren Nachkommen transformieren. Sie werden auch bei der Navigation nach der Suchvalidierung ausgeführt, um die Manipulation der Abfragezeichenkette zu ermöglichen.
Das folgende Beispiel zeigt, wie sichergestellt wird, dass für **jeden** Link, der erstellt wird, der Suchparameter rootValue hinzugefügt wird, *wenn* er Teil der aktuellen Suchparameter ist. Wenn ein Link rootValue innerhalb von search angibt, wird dieser Wert für die Link-Erstellung verwendet.
import { z } from 'zod'
import { createFileRoute } from '@tanstack/react-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/react-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 recht häufig vorkommt, bietet TanStack Router eine generische Implementierung zur Beibehaltung von Suchparametern über retainSearchParams.
import { z } from 'zod'
import { createFileRoute, retainSearchParams } from '@tanstack/react-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/react-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 häufiger Anwendungsfall ist das Entfernen von Suchparametern aus Links, wenn ihr Standardwert gesetzt ist. TanStack Router bietet eine generische Implementierung für diesen Anwendungsfall über stripSearchParams.
import { z } from 'zod'
import { createFileRoute, stripSearchParams } from '@tanstack/react-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/react-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/react-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/react-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.