Framework
Version
Integrationen

Navigation

Alles ist relativ

Ob Sie es glauben oder nicht, jede Navigation innerhalb einer App ist relativ, auch wenn Sie keine explizite relative Pfadsyntax verwenden (../../somewhere). Jedes Mal, wenn auf einen Link geklickt wird oder ein imperativer Navigationsaufruf erfolgt, gibt es immer einen Ursprungspfad und einen Zielpfad, was bedeutet, dass Sie von einer Route zu einer anderen Route navigieren.

TanStack Router behält dieses konstante Konzept der relativen Navigation bei jeder Navigation im Hinterkopf, sodass Sie in der API ständig zwei Eigenschaften sehen werden

  • from - Der Pfad der Ursprungsroute
  • to - Der Pfad der Zielroute

⚠️ Wenn kein from-Routenpfad angegeben wird, geht der Router davon aus, dass Sie von der Stammroute / aus navigieren und vervollständigt nur absolute Pfade. Schließlich müssen Sie wissen, woher Sie kommen, um zu wissen, wohin Sie gehen 😉.

Gemeinsame Navigations-API

Jede Navigations- und Routenabgleich-API in TanStack Router verwendet dieselbe Kernschnittstelle mit geringfügigen Unterschieden, je nach API. Das bedeutet, dass Sie Navigation und Routenabgleich einmal lernen und dieselbe Syntax und Konzepte in der gesamten Bibliothek verwenden können.

ToOptions-Schnittstelle

Dies ist die Kernschnittstelle ToOptions, die in jeder Navigations- und Routenabgleich-API verwendet wird

ts
type ToOptions<
  TRouteTree extends AnyRoute = AnyRoute,
  TFrom extends RoutePaths<TRouteTree> | string = string,
  TTo extends string = '',
> = {
  // `from` is an optional route ID or path. If it is not supplied, only absolute paths will be auto-completed and type-safe. It's common to supply the route.fullPath of the origin route you are rendering from for convenience. If you don't know the origin route, leave this empty and work with absolute paths or unsafe relative paths.
  from?: string
  // `to` can be an absolute route path or a relative path from the `from` option to a valid route path. ⚠️ Do not interpolate path params, hash or search params into the `to` options. Use the `params`, `search`, and `hash` options instead.
  to: string
  // `params` is either an object of path params to interpolate into the `to` option or a function that supplies the previous params and allows you to return new ones. This is the only way to interpolate dynamic parameters into the final URL. Depending on the `from` and `to` route, you may need to supply none, some or all of the path params. TypeScript will notify you of the required params if there are any.
  params:
    | Record<string, unknown>
    | ((prevParams: Record<string, unknown>) => Record<string, unknown>)
  // `search` is either an object of query params or a function that supplies the previous search and allows you to return new ones. Depending on the `from` and `to` route, you may need to supply none, some or all of the query params. TypeScript will notify you of the required search params if there are any.
  search:
    | Record<string, unknown>
    | ((prevSearch: Record<string, unknown>) => Record<string, unknown>)
  // `hash` is either a string or a function that supplies the previous hash and allows you to return a new one.
  hash?: string | ((prevHash: string) => string)
  // `state` is either an object of state or a function that supplies the previous state and allows you to return a new one. State is stored in the history API and can be useful for passing data between routes that you do not want to permanently store in URL search params.
  state?:
    | Record<string, any>
    | ((prevState: Record<string, unknown>) => Record<string, unknown>)
}
type ToOptions<
  TRouteTree extends AnyRoute = AnyRoute,
  TFrom extends RoutePaths<TRouteTree> | string = string,
  TTo extends string = '',
> = {
  // `from` is an optional route ID or path. If it is not supplied, only absolute paths will be auto-completed and type-safe. It's common to supply the route.fullPath of the origin route you are rendering from for convenience. If you don't know the origin route, leave this empty and work with absolute paths or unsafe relative paths.
  from?: string
  // `to` can be an absolute route path or a relative path from the `from` option to a valid route path. ⚠️ Do not interpolate path params, hash or search params into the `to` options. Use the `params`, `search`, and `hash` options instead.
  to: string
  // `params` is either an object of path params to interpolate into the `to` option or a function that supplies the previous params and allows you to return new ones. This is the only way to interpolate dynamic parameters into the final URL. Depending on the `from` and `to` route, you may need to supply none, some or all of the path params. TypeScript will notify you of the required params if there are any.
  params:
    | Record<string, unknown>
    | ((prevParams: Record<string, unknown>) => Record<string, unknown>)
  // `search` is either an object of query params or a function that supplies the previous search and allows you to return new ones. Depending on the `from` and `to` route, you may need to supply none, some or all of the query params. TypeScript will notify you of the required search params if there are any.
  search:
    | Record<string, unknown>
    | ((prevSearch: Record<string, unknown>) => Record<string, unknown>)
  // `hash` is either a string or a function that supplies the previous hash and allows you to return a new one.
  hash?: string | ((prevHash: string) => string)
  // `state` is either an object of state or a function that supplies the previous state and allows you to return a new one. State is stored in the history API and can be useful for passing data between routes that you do not want to permanently store in URL search params.
  state?:
    | Record<string, any>
    | ((prevState: Record<string, unknown>) => Record<string, unknown>)
}

🧠 Jedes Routenobjekt hat eine to-Eigenschaft, die als to für jede Navigations- oder Routenabgleich-API verwendet werden kann. Wo immer möglich, können Sie so reine Zeichenketten vermeiden und stattdessen typsichere Routenreferenzen verwenden

tsx
import { Route as aboutRoute } from './routes/about.tsx'

function Comp() {
  return <Link to={aboutRoute.to}>About</Link>
}
import { Route as aboutRoute } from './routes/about.tsx'

function Comp() {
  return <Link to={aboutRoute.to}>About</Link>
}

Dies ist die Kernschnittstelle NavigateOptions, die ToOptions erweitert. Jede API, die tatsächlich eine Navigation durchführt, verwendet diese Schnittstelle

ts
export type NavigateOptions<
  TRouteTree extends AnyRoute = AnyRoute,
  TFrom extends RoutePaths<TRouteTree> | string = string,
  TTo extends string = '',
> = ToOptions<TRouteTree, TFrom, TTo> & {
  // `replace` is a boolean that determines whether the navigation should replace the current history entry or push a new one.
  replace?: boolean
  // `resetScroll` is a boolean that determines whether scroll position will be reset to 0,0 after the location is committed to browser history.
  resetScroll?: boolean
  // `hashScrollIntoView` is a boolean or object that determines whether an id matching the hash will be scrolled into view after the location is committed to history.
  hashScrollIntoView?: boolean | ScrollIntoViewOptions
  // `viewTransition` is either a boolean or function that determines if and how the browser will call document.startViewTransition() when navigating.
  viewTransition?: boolean | ViewTransitionOptions
  // `ignoreBlocker` is a boolean that determines if navigation should ignore any blockers that might prevent it.
  ignoreBlocker?: boolean
  // `reloadDocument` is a boolean that determines if navigation to a route inside of router will trigger a full page load instead of the traditional SPA navigation.
  reloadDocument?: boolean
  // `href` is a string that can be used in place of `to` to navigate to a full built href, e.g. pointing to an external target.
  href?: string
}
export type NavigateOptions<
  TRouteTree extends AnyRoute = AnyRoute,
  TFrom extends RoutePaths<TRouteTree> | string = string,
  TTo extends string = '',
> = ToOptions<TRouteTree, TFrom, TTo> & {
  // `replace` is a boolean that determines whether the navigation should replace the current history entry or push a new one.
  replace?: boolean
  // `resetScroll` is a boolean that determines whether scroll position will be reset to 0,0 after the location is committed to browser history.
  resetScroll?: boolean
  // `hashScrollIntoView` is a boolean or object that determines whether an id matching the hash will be scrolled into view after the location is committed to history.
  hashScrollIntoView?: boolean | ScrollIntoViewOptions
  // `viewTransition` is either a boolean or function that determines if and how the browser will call document.startViewTransition() when navigating.
  viewTransition?: boolean | ViewTransitionOptions
  // `ignoreBlocker` is a boolean that determines if navigation should ignore any blockers that might prevent it.
  ignoreBlocker?: boolean
  // `reloadDocument` is a boolean that determines if navigation to a route inside of router will trigger a full page load instead of the traditional SPA navigation.
  reloadDocument?: boolean
  // `href` is a string that can be used in place of `to` to navigate to a full built href, e.g. pointing to an external target.
  href?: string
}

LinkOptions-Schnittstelle

Überall dort, wo ein tatsächlicher <a>-Tag verwendet wird, ist die Schnittstelle LinkOptions, die NavigateOptions erweitert, verfügbar

tsx
export type LinkOptions<
  TRouteTree extends AnyRoute = AnyRoute,
  TFrom extends RoutePaths<TRouteTree> | string = string,
  TTo extends string = '',
> = NavigateOptions<TRouteTree, TFrom, TTo> & {
  // The standard anchor tag target attribute
  target?: HTMLAnchorElement['target']
  // Defaults to `{ exact: false, includeHash: false }`
  activeOptions?: {
    exact?: boolean
    includeHash?: boolean
    includeSearch?: boolean
    explicitUndefined?: boolean
  }
  // If set, will preload the linked route on hover and cache it for this many milliseconds in hopes that the user will eventually navigate there.
  preload?: false | 'intent'
  // Delay intent preloading by this many milliseconds. If the intent exits before this delay, the preload will be cancelled.
  preloadDelay?: number
  // If true, will render the link without the href attribute
  disabled?: boolean
}
export type LinkOptions<
  TRouteTree extends AnyRoute = AnyRoute,
  TFrom extends RoutePaths<TRouteTree> | string = string,
  TTo extends string = '',
> = NavigateOptions<TRouteTree, TFrom, TTo> & {
  // The standard anchor tag target attribute
  target?: HTMLAnchorElement['target']
  // Defaults to `{ exact: false, includeHash: false }`
  activeOptions?: {
    exact?: boolean
    includeHash?: boolean
    includeSearch?: boolean
    explicitUndefined?: boolean
  }
  // If set, will preload the linked route on hover and cache it for this many milliseconds in hopes that the user will eventually navigate there.
  preload?: false | 'intent'
  // Delay intent preloading by this many milliseconds. If the intent exits before this delay, the preload will be cancelled.
  preloadDelay?: number
  // If true, will render the link without the href attribute
  disabled?: boolean
}

Mit relativer Navigation und all den Schnittstellen im Hinterkopf, sprechen wir nun über die verschiedenen Navigations-APIs, die Ihnen zur Verfügung stehen

  • Die <Link>-Komponente
    • Generiert ein tatsächliches <a>-Tag mit einem gültigen href, das angeklickt oder sogar mit Cmd/Strg + Klick in einem neuen Tab geöffnet werden kann
  • Der useNavigate()-Hook
    • Wo immer möglich, sollte die Link-Komponente für die Navigation verwendet werden, aber manchmal müssen Sie als Ergebnis eines Nebeneffekts imperativ navigieren. useNavigate gibt eine Funktion zurück, die aufgerufen werden kann, um eine sofortige clientseitige Navigation durchzuführen.
  • Die <Navigate>-Komponente
    • Rendert nichts und führt eine sofortige clientseitige Navigation durch.
  • Die Methode router.navigate()
    • Dies ist die leistungsstärkste Navigations-API in TanStack Router. Ähnlich wie useNavigate navigiert sie imperativ, ist aber überall verfügbar, wo Sie Zugriff auf Ihren Router haben.

⚠️ Keine dieser APIs ist ein Ersatz für serverseitige Weiterleitungen. Wenn Sie einen Benutzer sofort von einer Route zu einer anderen weiterleiten müssen, bevor Sie Ihre Anwendung mounten, verwenden Sie eine serverseitige Weiterleitung anstelle einer clientseitigen Navigation.

Die Link-Komponente ist die gebräuchlichste Methode, um innerhalb einer App zu navigieren. Sie rendert ein tatsächliches <a>-Tag mit einem gültigen href-Attribut, das angeklickt oder sogar mit Cmd/Strg + Klick in einem neuen Tab geöffnet werden kann. Sie unterstützt auch alle normalen <a>-Attribute, einschließlich target, um Links in neuen Fenstern zu öffnen usw.

Zusätzlich zur Schnittstelle LinkOptions unterstützt die Link-Komponente die folgenden Props

tsx
export type LinkProps<
  TFrom extends RoutePaths<RegisteredRouter['routeTree']> | string = string,
  TTo extends string = '',
> = LinkOptions<RegisteredRouter['routeTree'], TFrom, TTo> & {
  // A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
  activeProps?:
    | FrameworkHTMLAnchorTagAttributes
    | (() => FrameworkHTMLAnchorAttributes)
  // A function that returns additional props for the `inactive` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
  inactiveProps?:
    | FrameworkHTMLAnchorAttributes
    | (() => FrameworkHTMLAnchorAttributes)
}
export type LinkProps<
  TFrom extends RoutePaths<RegisteredRouter['routeTree']> | string = string,
  TTo extends string = '',
> = LinkOptions<RegisteredRouter['routeTree'], TFrom, TTo> & {
  // A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
  activeProps?:
    | FrameworkHTMLAnchorTagAttributes
    | (() => FrameworkHTMLAnchorAttributes)
  // A function that returns additional props for the `inactive` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
  inactiveProps?:
    | FrameworkHTMLAnchorAttributes
    | (() => FrameworkHTMLAnchorAttributes)
}

Lassen Sie uns einen einfachen statischen Link erstellen!

tsx
import { Link } from '@tanstack/react-router'

const link = <Link to="/about">About</Link>
import { Link } from '@tanstack/react-router'

const link = <Link to="/about">About</Link>

Dynamische Links sind Links, die dynamische Segmente enthalten. Zum Beispiel könnte ein Link zu einem Blogbeitrag so aussehen

tsx
const link = (
  <Link
    to="/blog/post/$postId"
    params={{
      postId: 'my-first-blog-post',
    }}
  >
    Blog Post
  </Link>
)
const link = (
  <Link
    to="/blog/post/$postId"
    params={{
      postId: 'my-first-blog-post',
    }}
  >
    Blog Post
  </Link>
)

Beachten Sie, dass dynamische Segmentparameter normalerweise string-Werte sind, aber sie können auch jeder andere Typ sein, zu dem Sie sie in Ihren Routenoptionen parsen. In jedem Fall wird der Typ zur Kompilierzeit überprüft, um sicherzustellen, dass Sie den richtigen Typ übergeben.

Standardmäßig sind alle Links absolut, es sei denn, ein from-Routenpfad wird bereitgestellt. Das bedeutet, dass der obige Link immer zur Route /about navigiert, unabhängig davon, auf welcher Route Sie sich gerade befinden.

Relative Links können mit einem from-Routenpfad kombiniert werden. Wenn kein from-Routenpfad bereitgestellt wird, werden relative Pfade standardmäßig zur aktuell aktiven Position verwendet.

tsx
const postIdRoute = createRoute({
  path: '/blog/post/$postId',
})

const link = (
  <Link from={postIdRoute.fullPath} to="../categories">
    Categories
  </Link>
)
const postIdRoute = createRoute({
  path: '/blog/post/$postId',
})

const link = (
  <Link from={postIdRoute.fullPath} to="../categories">
    Categories
  </Link>
)

Wie oben gezeigt, ist es üblich, route.fullPath als from-Routenpfad anzugeben. Das liegt daran, dass route.fullPath eine Referenz ist, die sich ändert, wenn Sie Ihre Anwendung refaktorieren. Manchmal ist es jedoch nicht möglich, die Route direkt zu importieren. In diesem Fall ist es in Ordnung, den Routenpfad direkt als Zeichenkette anzugeben. Er wird trotzdem wie gewohnt typsicher geprüft!

Spezielle relative Pfade: "." und ".."

Oft möchten Sie möglicherweise den aktuellen Standort oder einen anderen from-Pfad neu laden, um beispielsweise die Loader auf der aktuellen und/oder übergeordneten Routen erneut auszuführen oder vielleicht zu einer übergeordneten Route zurückzukehren. Dies kann erreicht werden, indem ein to-Routenpfad von "." angegeben wird, der den aktuellen Standort oder den angegebenen from-Pfad neu lädt.

Eine weitere häufige Anforderung ist die Navigation eine Route zurück relativ zum aktuellen Standort oder einem anderen Pfad. Durch Angabe eines to-Routenpfads von ".." wird die Navigation zur ersten übergeordneten Route aufgelöst, die dem aktuellen Standort vorausgeht.

tsx
export const Route = createFileRoute('/posts/$postId')({
  component: PostComponent,
})

function PostComponent() {
  return (
    <div>
      <Link to=".">Reload the current route of /posts/$postId</Link>
      <Link to="..">Navigate back to /posts</Link>
      // the below are all equivalent
      <Link to="/posts">Navigate back to /posts</Link>
      <Link from="/posts" to=".">
        Navigate back to /posts
      </Link>
      // the below are all equivalent
      <Link to="/">Navigate to root</Link>
      <Link from="/posts" to="..">
        Navigate to root
      </Link>
    </div>
  )
}
export const Route = createFileRoute('/posts/$postId')({
  component: PostComponent,
})

function PostComponent() {
  return (
    <div>
      <Link to=".">Reload the current route of /posts/$postId</Link>
      <Link to="..">Navigate back to /posts</Link>
      // the below are all equivalent
      <Link to="/posts">Navigate back to /posts</Link>
      <Link from="/posts" to=".">
        Navigate back to /posts
      </Link>
      // the below are all equivalent
      <Link to="/">Navigate to root</Link>
      <Link from="/posts" to="..">
        Navigate to root
      </Link>
    </div>
  )
}

Search-Parameter sind eine großartige Möglichkeit, zusätzliche Kontexte für eine Route bereitzustellen. Sie möchten beispielsweise eine Suchanfrage für eine Suchseite bereitstellen

tsx
const link = (
  <Link
    to="/search"
    search={{
      query: 'tanstack',
    }}
  >
    Search
  </Link>
)
const link = (
  <Link
    to="/search"
    search={{
      query: 'tanstack',
    }}
  >
    Search
  </Link>
)

Es ist auch üblich, einen einzelnen Search-Parameter aktualisieren zu wollen, ohne andere Informationen über die vorhandene Route bereitzustellen. Sie möchten beispielsweise die Seitennummer eines Suchergebnisses aktualisieren

tsx
const link = (
  <Link
    to="."
    search={(prev) => ({
      ...prev,
      page: prev.page + 1,
    })}
  >
    Next Page
  </Link>
)
const link = (
  <Link
    to="."
    search={(prev) => ({
      ...prev,
      page: prev.page + 1,
    })}
  >
    Next Page
  </Link>
)

Typsicherheit bei Search Params

Search-Parameter sind ein hochdynamischer Mechanismus zur Zustandsverwaltung, daher ist es wichtig sicherzustellen, dass Sie die richtigen Typen an Ihre Search-Parameter übergeben. In einem späteren Abschnitt werden wir detailliert sehen, wie Sie Search-Parameter-Typen sowie andere großartige Funktionen validieren und sicherstellen können!

Hash-Links sind eine großartige Möglichkeit, zu einem bestimmten Abschnitt einer Seite zu verlinken. Sie möchten beispielsweise zu einem bestimmten Abschnitt eines Blogbeitrags verlinken

tsx
const link = (
  <Link
    to="/blog/post/$postId"
    params={{
      postId: 'my-first-blog-post',
    }}
    hash="section-1"
  >
    Section 1
  </Link>
)
const link = (
  <Link
    to="/blog/post/$postId"
    params={{
      postId: 'my-first-blog-post',
    }}
    hash="section-1"
  >
    Section 1
  </Link>
)

Optionale Pfadparameter bieten flexible Navigationsmuster, bei denen Sie Parameter nach Bedarf einschließen oder weglassen können. Optionale Parameter verwenden die Syntax {-$paramName} und bieten eine detaillierte Kontrolle über die URL-Struktur.

Parametererbe vs. Entfernung

Bei der Navigation mit optionalen Parametern haben Sie zwei Hauptstrategien

Erben aktueller Parameter Verwenden Sie params: {}, um alle aktuellen Routenparameter zu erben

tsx
// Inherits current route parameters
<Link to="/posts/{-$category}" params={{}}>
  All Posts
</Link>
// Inherits current route parameters
<Link to="/posts/{-$category}" params={{}}>
  All Posts
</Link>

Entfernen von Parametern
Setzen Sie Parameter auf undefined, um sie explizit zu entfernen

tsx
// Removes the category parameter
<Link to="/posts/{-$category}" params={{ category: undefined }}>
  All Posts
</Link>
// Removes the category parameter
<Link to="/posts/{-$category}" params={{ category: undefined }}>
  All Posts
</Link>

Grundlegende Navigation mit optionalen Parametern

tsx
// 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 using parameter inheritance
<Link
  to="/posts/{-$category}"
  params={{}}
>
  Current Category
</Link>
// 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 using parameter inheritance
<Link
  to="/posts/{-$category}"
  params={{}}
>
  Current Category
</Link>

Funktionsbasierte Parameteraktualisierungen

Funktionsbasierte Parameteraktualisierungen sind besonders nützlich bei optionalen Parametern

tsx
// Remove a parameter using function syntax
<Link
  to="/posts/{-$category}"
  params={(prev) => ({ ...prev, category: undefined })}
>
  Clear Category
</Link>

// Update a parameter while keeping others
<Link
  to="/articles/{-$category}/{-$slug}"
  params={(prev) => ({ ...prev, category: 'news' })}
>
  News Articles
</Link>

// Conditionally set parameters
<Link
  to="/posts/{-$category}"
  params={(prev) => ({
    ...prev,
    category: someCondition ? 'tech' : undefined
  })}
>
  Conditional Category
</Link>
// Remove a parameter using function syntax
<Link
  to="/posts/{-$category}"
  params={(prev) => ({ ...prev, category: undefined })}
>
  Clear Category
</Link>

// Update a parameter while keeping others
<Link
  to="/articles/{-$category}/{-$slug}"
  params={(prev) => ({ ...prev, category: 'news' })}
>
  News Articles
</Link>

// Conditionally set parameters
<Link
  to="/posts/{-$category}"
  params={(prev) => ({
    ...prev,
    category: someCondition ? 'tech' : undefined
  })}
>
  Conditional Category
</Link>

Mehrere optionale Parameter

Beim Arbeiten mit mehreren optionalen Parametern können Sie mischen und anpassen, welche davon eingeschlossen werden sollen

tsx
// Navigate with some optional parameters
<Link
  to="/posts/{-$category}/{-$slug}"
  params={{ category: 'tech', slug: undefined }}
>
  Tech Posts
</Link>

// Remove all optional parameters
<Link
  to="/posts/{-$category}/{-$slug}"
  params={{ category: undefined, slug: undefined }}
>
  All Posts
</Link>

// Set multiple parameters
<Link
  to="/posts/{-$category}/{-$slug}"
  params={{ category: 'tech', slug: 'react-tips' }}
>
  Specific Post
</Link>
// Navigate with some optional parameters
<Link
  to="/posts/{-$category}/{-$slug}"
  params={{ category: 'tech', slug: undefined }}
>
  Tech Posts
</Link>

// Remove all optional parameters
<Link
  to="/posts/{-$category}/{-$slug}"
  params={{ category: undefined, slug: undefined }}
>
  All Posts
</Link>

// Set multiple parameters
<Link
  to="/posts/{-$category}/{-$slug}"
  params={{ category: 'tech', slug: 'react-tips' }}
>
  Specific Post
</Link>

Gemischte erforderliche und optionale Parameter

Optionale Parameter funktionieren nahtlos mit erforderlichen Parametern

tsx
// Required 'id', optional 'tab'
<Link
  to="/users/$id/{-$tab}"
  params={{ id: '123', tab: 'settings' }}
>
  User Settings
</Link>

// Remove optional parameter while keeping required
<Link
  to="/users/$id/{-$tab}"
  params={{ id: '123', tab: undefined }}
>
  User Profile
</Link>

// Use function style with mixed parameters
<Link
  to="/users/$id/{-$tab}"
  params={(prev) => ({ ...prev, tab: 'notifications' })}
>
  User Notifications
</Link>
// Required 'id', optional 'tab'
<Link
  to="/users/$id/{-$tab}"
  params={{ id: '123', tab: 'settings' }}
>
  User Settings
</Link>

// Remove optional parameter while keeping required
<Link
  to="/users/$id/{-$tab}"
  params={{ id: '123', tab: undefined }}
>
  User Profile
</Link>

// Use function style with mixed parameters
<Link
  to="/users/$id/{-$tab}"
  params={(prev) => ({ ...prev, tab: 'notifications' })}
>
  User Notifications
</Link>

Erweiterte Muster für optionale Parameter

Präfix- und Suffixparameter Optionale Parameter mit Präfix/Suffix funktionieren mit der Navigation

tsx
// Navigate to file with optional name
<Link
  to="/files/prefix{-$name}.txt"
  params={{ name: 'document' }}
>
  Document File
</Link>

// Navigate to file without optional name
<Link
  to="/files/prefix{-$name}.txt"
  params={{ name: undefined }}
>
  Default File
</Link>
// Navigate to file with optional name
<Link
  to="/files/prefix{-$name}.txt"
  params={{ name: 'document' }}
>
  Document File
</Link>

// Navigate to file without optional name
<Link
  to="/files/prefix{-$name}.txt"
  params={{ name: undefined }}
>
  Default File
</Link>

Alle optionalen Parameter Routen, bei denen alle Parameter optional sind

tsx
// Navigate to specific date
<Link
  to="/{-$year}/{-$month}/{-$day}"
  params={{ year: '2023', month: '12', day: '25' }}
>
  Christmas 2023
</Link>

// Navigate to partial date
<Link
  to="/{-$year}/{-$month}/{-$day}"
  params={{ year: '2023', month: '12', day: undefined }}
>
  December 2023
</Link>

// Navigate to root with all parameters removed
<Link
  to="/{-$year}/{-$month}/{-$day}"
  params={{ year: undefined, month: undefined, day: undefined }}
>
  Home
</Link>
// Navigate to specific date
<Link
  to="/{-$year}/{-$month}/{-$day}"
  params={{ year: '2023', month: '12', day: '25' }}
>
  Christmas 2023
</Link>

// Navigate to partial date
<Link
  to="/{-$year}/{-$month}/{-$day}"
  params={{ year: '2023', month: '12', day: undefined }}
>
  December 2023
</Link>

// Navigate to root with all parameters removed
<Link
  to="/{-$year}/{-$month}/{-$day}"
  params={{ year: undefined, month: undefined, day: undefined }}
>
  Home
</Link>

Optionale Parameter lassen sich gut mit Search-Parametern kombinieren

tsx
// Combine optional path params with search params
<Link
  to="/posts/{-$category}"
  params={{ category: 'tech' }}
  search={{ page: 1, sort: 'newest' }}
>
  Tech Posts - Page 1
</Link>

// Remove path param but keep search params
<Link
  to="/posts/{-$category}"
  params={{ category: undefined }}
  search={(prev) => prev}
>
  All Posts - Same Filters
</Link>
// Combine optional path params with search params
<Link
  to="/posts/{-$category}"
  params={{ category: 'tech' }}
  search={{ page: 1, sort: 'newest' }}
>
  Tech Posts - Page 1
</Link>

// Remove path param but keep search params
<Link
  to="/posts/{-$category}"
  params={{ category: undefined }}
  search={(prev) => prev}
>
  All Posts - Same Filters
</Link>

Imperative Navigation mit optionalen Parametern

Alle gleichen Muster funktionieren auch bei imperativer Navigation

tsx
function Component() {
  const navigate = useNavigate()

  const clearFilters = () => {
    navigate({
      to: '/posts/{-$category}/{-$tag}',
      params: { category: undefined, tag: undefined },
    })
  }

  const setCategory = (category: string) => {
    navigate({
      to: '/posts/{-$category}/{-$tag}',
      params: (prev) => ({ ...prev, category }),
    })
  }

  const applyFilters = (category?: string, tag?: string) => {
    navigate({
      to: '/posts/{-$category}/{-$tag}',
      params: { category, tag },
    })
  }
}
function Component() {
  const navigate = useNavigate()

  const clearFilters = () => {
    navigate({
      to: '/posts/{-$category}/{-$tag}',
      params: { category: undefined, tag: undefined },
    })
  }

  const setCategory = (category: string) => {
    navigate({
      to: '/posts/{-$category}/{-$tag}',
      params: (prev) => ({ ...prev, category }),
    })
  }

  const applyFilters = (category?: string, tag?: string) => {
    navigate({
      to: '/posts/{-$category}/{-$tag}',
      params: { category, tag },
    })
  }
}

active & inactive Props

Die Link-Komponente unterstützt zwei zusätzliche Props: activeProps und inactiveProps. Diese Props sind Funktionen, die zusätzliche Props für die aktiven und inaktiven Zustände des Links zurückgeben. Alle Props außer Stilen und Klassen, die hier übergeben werden, überschreiben die ursprünglichen Props, die an Link übergeben wurden. Alle übergebenen Stile oder Klassen werden zusammengeführt.

Hier ist ein Beispiel

tsx
const link = (
  <Link
    to="/blog/post/$postId"
    params={{
      postId: 'my-first-blog-post',
    }}
    activeProps={{
      style: {
        fontWeight: 'bold',
      },
    }}
  >
    Section 1
  </Link>
)
const link = (
  <Link
    to="/blog/post/$postId"
    params={{
      postId: 'my-first-blog-post',
    }}
    activeProps={{
      style: {
        fontWeight: 'bold',
      },
    }}
  >
    Section 1
  </Link>
)

Das Attribut data-status

Zusätzlich zu den Props activeProps und inactiveProps fügt die Link-Komponente ein data-status-Attribut zum gerenderten Element hinzu, wenn es sich im aktiven Zustand befindet. Dieses Attribut ist entweder active oder undefined, abhängig vom aktuellen Zustand des Links. Dies kann nützlich sein, wenn Sie Datenattribute zum Stylen Ihrer Links anstelle von Props bevorzugen.

activeOptions

Die Link-Komponente verfügt über eine Eigenschaft activeOptions, die einige Optionen zur Bestimmung bietet, ob ein Link aktiv ist oder nicht. Die folgende Schnittstelle beschreibt diese Optionen

tsx
export interface ActiveOptions {
  // If true, the link will be active if the current route matches the `to` route path exactly (no children routes)
  // Defaults to `false`
  exact?: boolean
  // If true, the link will only be active if the current URL hash matches the `hash` prop
  // Defaults to `false`
  includeHash?: boolean // Defaults to false
  // If true, the link will only be active if the current URL search params inclusively match the `search` prop
  // Defaults to `true`
  includeSearch?: boolean
  // This modifies the `includeSearch` behavior.
  // If true,  properties in `search` that are explicitly `undefined` must NOT be present in the current URL search params for the link to be active.
  // defaults to `false`
  explicitUndefined?: boolean
}
export interface ActiveOptions {
  // If true, the link will be active if the current route matches the `to` route path exactly (no children routes)
  // Defaults to `false`
  exact?: boolean
  // If true, the link will only be active if the current URL hash matches the `hash` prop
  // Defaults to `false`
  includeHash?: boolean // Defaults to false
  // If true, the link will only be active if the current URL search params inclusively match the `search` prop
  // Defaults to `true`
  includeSearch?: boolean
  // This modifies the `includeSearch` behavior.
  // If true,  properties in `search` that are explicitly `undefined` must NOT be present in the current URL search params for the link to be active.
  // defaults to `false`
  explicitUndefined?: boolean
}

Standardmäßig wird geprüft, ob der resultierende Pfadname ein Präfix der aktuellen Route ist. Wenn Suchparameter angegeben sind, wird geprüft, ob diese die im aktuellen Standort vorhandenen Parameter inklusiv abgleichen. Hashes werden standardmäßig nicht geprüft.

Wenn Sie sich beispielsweise auf der Route /blog/post/my-first-blog-post befinden, sind die folgenden Links aktiv

tsx
const link1 = (
  <Link to="/blog/post/$postId" params={{ postId: 'my-first-blog-post' }}>
    Blog Post
  </Link>
)
const link2 = <Link to="/blog/post">Blog Post</Link>
const link3 = <Link to="/blog">Blog Post</Link>
const link1 = (
  <Link to="/blog/post/$postId" params={{ postId: 'my-first-blog-post' }}>
    Blog Post
  </Link>
)
const link2 = <Link to="/blog/post">Blog Post</Link>
const link3 = <Link to="/blog">Blog Post</Link>

Die folgenden Links sind jedoch nicht aktiv

tsx
const link4 = (
  <Link to="/blog/post/$postId" params={{ postId: 'my-second-blog-post' }}>
    Blog Post
  </Link>
)
const link4 = (
  <Link to="/blog/post/$postId" params={{ postId: 'my-second-blog-post' }}>
    Blog Post
  </Link>
)

Es ist üblich, dass einige Links nur aktiv sind, wenn sie eine exakte Übereinstimmung sind. Ein gutes Beispiel hierfür wäre ein Link zur Startseite. In solchen Fällen können Sie die Option exact: true übergeben

tsx
const link = (
  <Link to="/" activeOptions={{ exact: true }}>
    Home
  </Link>
)
const link = (
  <Link to="/" activeOptions={{ exact: true }}>
    Home
  </Link>
)

Dies stellt sicher, dass der Link nicht aktiv ist, wenn Sie sich auf einer untergeordneten Route befinden.

Ein paar weitere Optionen, die Sie beachten sollten

  • Wenn Sie den Hash in Ihren Abgleich einbeziehen möchten, können Sie die Option includeHash: true übergeben
  • Wenn Sie die Suchparameter nicht in Ihren Abgleich einbeziehen möchten, können Sie die Option includeSearch: false übergeben

isActive an Kinder übergeben

Die Link-Komponente akzeptiert eine Funktion als Kinder, wodurch Sie ihre isActive-Eigenschaft an Kinder weitergeben können. Sie könnten beispielsweise eine Kindkomponente basierend darauf stylen, ob der übergeordnete Link aktiv ist

tsx
const link = (
  <Link to="/blog/post">
    {({ isActive }) => {
      return (
        <>
          <span>My Blog Post</span>
          <icon className={isActive ? 'active' : 'inactive'} />
        </>
      )
    }}
  </Link>
)
const link = (
  <Link to="/blog/post">
    {({ isActive }) => {
      return (
        <>
          <span>My Blog Post</span>
          <icon className={isActive ? 'active' : 'inactive'} />
        </>
      )
    }}
  </Link>
)

Die Link-Komponente unterstützt die automatische Vorabladung von Routen bei Absicht (derzeit Hover oder Touchstart). Dies kann als Standard in den Router-Optionen konfiguriert werden (worüber wir bald mehr sprechen werden) oder durch Übergabe eines preload='intent'-Props an die Link-Komponente. Hier ist ein Beispiel

tsx
const link = (
  <Link to="/blog/post/$postId" preload="intent">
    Blog Post
  </Link>
)
const link = (
  <Link to="/blog/post/$postId" preload="intent">
    Blog Post
  </Link>
)

Mit aktivierter Vorabladung und relativ schnellen asynchronen Routenabhängigkeiten (falls vorhanden) kann dieser einfache Trick die wahrgenommene Leistung Ihrer Anwendung mit sehr geringem Aufwand steigern.

Was noch besser ist, ist, dass durch die Verwendung einer Cache-First-Bibliothek wie @tanstack/query, vorab geladene Routen bestehen bleiben und für eine Stale-While-Revalidate-Erfahrung bereit sind, wenn der Benutzer sich später entscheidet, zu der Route zu navigieren.

Zusammen mit der Vorabladung gibt es eine konfigurierbare Verzögerung, die bestimmt, wie lange ein Benutzer über einen Link schweben muss, um die absichtsbasierte Vorabladung auszulösen. Die Standardverzögerung beträgt 50 Millisekunden, aber Sie können dies ändern, indem Sie einen preloadDelay-Prop an die Link-Komponente mit der gewünschten Anzahl von Millisekunden übergeben

tsx
const link = (
  <Link to="/blog/post/$postId" preload="intent" preloadDelay={100}>
    Blog Post
  </Link>
)
const link = (
  <Link to="/blog/post/$postId" preload="intent" preloadDelay={100}>
    Blog Post
  </Link>
)

useNavigate

⚠️ Aufgrund der integrierten Funktionen der Link-Komponente in Bezug auf href, Cmd/Strg + Klickbarkeit und aktive/inaktive Fähigkeiten wird empfohlen, die Link-Komponente anstelle von useNavigate für alles zu verwenden, womit der Benutzer interagieren kann (z. B. Links, Schaltflächen). Es gibt jedoch einige Fälle, in denen useNavigate erforderlich ist, um Nebeneffektnavigationen zu handhaben (z. B. eine erfolgreiche asynchrone Aktion, die zu einer Navigation führt).

Der useNavigate-Hook gibt eine navigate-Funktion zurück, die aufgerufen werden kann, um imperativ zu navigieren. Dies ist eine großartige Möglichkeit, von einem Nebeneffekt (z. B. einer erfolgreichen asynchronen Aktion) zu einer Route zu navigieren. Hier ist ein Beispiel

tsx
function Component() {
  const navigate = useNavigate({ from: '/posts/$postId' })

  const handleSubmit = async (e: FrameworkFormEvent) => {
    e.preventDefault()

    const response = await fetch('/posts', {
      method: 'POST',
      body: JSON.stringify({ title: 'My First Post' }),
    })

    const { id: postId } = await response.json()

    if (response.ok) {
      navigate({ to: '/posts/$postId', params: { postId } })
    }
  }
}
function Component() {
  const navigate = useNavigate({ from: '/posts/$postId' })

  const handleSubmit = async (e: FrameworkFormEvent) => {
    e.preventDefault()

    const response = await fetch('/posts', {
      method: 'POST',
      body: JSON.stringify({ title: 'My First Post' }),
    })

    const { id: postId } = await response.json()

    if (response.ok) {
      navigate({ to: '/posts/$postId', params: { postId } })
    }
  }
}

🧠 Wie oben gezeigt, können Sie die Option from übergeben, um die Route anzugeben, von der in dem Hook-Aufruf navigiert werden soll. Obwohl dies auch möglich ist, wenn Sie sie jedes Mal, wenn Sie sie aufrufen, in der resultierenden navigate-Funktion übergeben, wird empfohlen, sie hier zu übergeben, um potenzielle Fehler zu reduzieren und auch weniger tippen zu müssen!

Die von useNavigate zurückgegebene navigate-Funktion akzeptiert die NavigateOptions-Schnittstelle

Gelegentlich müssen Sie möglicherweise sofort navigieren, wenn eine Komponente gemountet wird. Ihr erster Gedanke könnte sein, zu useNavigate und einem sofortigen Nebeneffekt (z. B. useEffect) zu greifen, aber das ist unnötig. Stattdessen können Sie die Navigate-Komponente rendern, um dasselbe Ergebnis zu erzielen

tsx
function Component() {
  return <Navigate to="/posts/$postId" params={{ postId: 'my-first-post' }} />
}
function Component() {
  return <Navigate to="/posts/$postId" params={{ postId: 'my-first-post' }} />
}

Betrachten Sie die Navigate-Komponente als eine Möglichkeit, sofort zu einer Route zu navigieren, wenn eine Komponente gemountet wird. Dies ist eine großartige Möglichkeit, nur clientseitige Weiterleitungen zu handhaben. Sie ist auf keinen Fall ein Ersatz für die verantwortungsvolle Handhabung serverseitiger Weiterleitungen auf dem Server.

router.navigate

Die Methode router.navigate ist dieselbe wie die von useNavigate zurückgegebene navigate-Funktion und akzeptiert dieselbe NavigateOptions-Schnittstelle. Im Gegensatz zum useNavigate-Hook ist sie überall verfügbar, wo Ihre router-Instanz verfügbar ist und ist somit eine großartige Möglichkeit, imperativ von überall in Ihrer Anwendung zu navigieren, auch außerhalb Ihres Frameworks.

useMatchRoute und <MatchRoute>

Der Hook useMatchRoute und die Komponente <MatchRoute> sind dasselbe, aber der Hook ist etwas flexibler. Beide akzeptieren die Standard-Navigations- ToOptions-Schnittstelle entweder als Optionen oder Props und geben true/false zurück, ob diese Route aktuell übereinstimmt. Sie verfügt auch über eine praktische pending-Option, die true zurückgibt, wenn die Route gerade bearbeitet wird (z. B. eine Route, die gerade zu dieser Route wechselt). Dies kann äußerst nützlich sein, um optimistische Benutzeroberflächen rund um die Navigation eines Benutzers anzuzeigen

tsx
function Component() {
  return (
    <div>
      <Link to="/users">
        Users
        <MatchRoute to="/users" pending>
          <Spinner />
        </MatchRoute>
      </Link>
    </div>
  )
}
function Component() {
  return (
    <div>
      <Link to="/users">
        Users
        <MatchRoute to="/users" pending>
          <Spinner />
        </MatchRoute>
      </Link>
    </div>
  )
}

Die Komponentenversion <MatchRoute> kann auch mit einer Funktion als Kinder verwendet werden, um etwas zu rendern, wenn die Route übereinstimmt

tsx
function Component() {
  return (
    <div>
      <Link to="/users">
        Users
        <MatchRoute to="/users" pending>
          {(match) => {
            return <Spinner show={match} />
          }}
        </MatchRoute>
      </Link>
    </div>
  )
}
function Component() {
  return (
    <div>
      <Link to="/users">
        Users
        <MatchRoute to="/users" pending>
          {(match) => {
            return <Spinner show={match} />
          }}
        </MatchRoute>
      </Link>
    </div>
  )
}

Die Hook-Version useMatchRoute gibt eine Funktion zurück, die programmatisch aufgerufen werden kann, um zu überprüfen, ob eine Route übereinstimmt

tsx
function Component() {
  const matchRoute = useMatchRoute()

  useEffect(() => {
    if (matchRoute({ to: '/users', pending: true })) {
      console.info('The /users route is matched and pending')
    }
  })

  return (
    <div>
      <Link to="/users">Users</Link>
    </div>
  )
}
function Component() {
  const matchRoute = useMatchRoute()

  useEffect(() => {
    if (matchRoute({ to: '/users', pending: true })) {
      console.info('The /users route is matched and pending')
    }
  })

  return (
    <div>
      <Link to="/users">Users</Link>
    </div>
  )
}

Puh! Das ist eine Menge Navigation! Dennoch fühlen Sie sich hoffentlich ziemlich gut im Umgang mit Ihrer Anwendung. Machen wir weiter!

Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Bytes abonnieren

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

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

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

Bytes

Kein Spam. Jederzeit kündbar.