Euen Diese Dokumente sind nur für Wouter v3. Die Dokumentation finden Sie hier für [email protected]
<Router /> -Komponente, es ist vollständig optional .Route , Link , Switch und Redirect .useLocation , useRoute und useRouter . ... Ich liebe Wouter. Es ist winzig, umarmt die Haken und hat eine intuitive und Barebones -API. Ich kann alles erreichen, was ich mit React-Router mit Wouters kann, und es fühlt sich einfach minimalistischer an, ohne unpraktisch zu sein.
Matt Miller , ein umfassendes React -Ökosystem für 2020
Wouter bietet eine einfache API, die viele Entwickler und Bibliotheksautoren zu schätzen wissen. Einige bemerkenswerte Projekte, die Wouter verwenden: Ultra , React-Drei-Faser , Sunmao UI , Millionen und vieles mehr.
Erste Schritte
Wouter -API
Haken -API
useRoute : Routenübereinstimmung und ParameteruseLocation : Mit der Geschichte arbeitenuseParams : Extrahieren übereinstimmter ParameteruseSearch : Abfragen von ZeichenfolgenuseRouter : Zugriff auf das Router -ObjektKomponenten -API
<Route path={pattern} /><Link href={path} /><Switch /><Redirect to={path} /><Router hook={hook} parser={fn} base={basepath} />FAQ- und Code -Rezepte
Anerkennung
Fügen Sie zunächst Ihr Projekt hinzu.
npm i wouter Oder, wenn Sie den folgenden Befehl verwenden npm i wouter-preact verwenden kann.
Schauen Sie sich diese einfache Demo -App unten an. Es umfasst keine Haken und andere Funktionen wie verschachteltes Routing, aber es ist ein guter Ausgangspunkt für diejenigen, die vom React -Router migrieren.
import { Link , Route , Switch } from "wouter" ;
const App = ( ) => (
< >
< Link href = "/users/1" > Profile </ Link >
< Route path = "/about" > About Us </ Route >
{ /*
Routes below are matched exclusively -
the first matched route gets rendered
*/ }
< Switch >
< Route path = "/inbox" component = { InboxPage } />
< Route path = "/users/:name" >
{ ( params ) => < > Hello, { params . name } ! </ > }
</ Route >
{ /* Default route in a switch */ }
< Route > 404: No such page! </ Route >
</ Switch >
</ >
) ; Diese Bibliothek ist für die Kompatibilität von ES2020+ ausgelegt. Wenn Sie ältere Browser unterstützen müssen, stellen Sie sicher, dass Sie node_modules umsetzen. Darüber hinaus beträgt die minimal unterstützte Typscript -Version 4.1, um die Inferenz des Routenparameters zu unterstützen.
Wouter ist mit drei Arten von APIs ausgestattet: Low-Level -Standalone-Standorthaken , Haken für Routing- und Musteranpassung und traditionellere Komponenten-basierte API ähnlich wie bei React Routers.
Sie können kostenlos auswählen, was für Sie funktioniert: Verwenden Sie Standorthaken, wenn Sie Ihre App so klein wie möglich halten möchten, und benötigen kein Musteranpassung. Verwenden Sie Routing -Hooks, wenn Sie benutzerdefinierte Routing -Komponenten erstellen möchten. Oder wenn Sie eine traditionelle App mit Seiten und Navigation bauen - können Komponenten nützlich sein.
Weitere Informationen zu FAQ- und Code-Rezepten finden Sie unter fortgeschrittenere Dinge wie aktive Links, Standardrouten, serverseitiges Rendering usw.
Standorthaken
Diese können getrennt vom Hauptmodul verwendet werden und haben eine Schnittstelle, die dem useState ähnelt. Diese Haken unterstützen Nisten, Basispfad und Routenabgleich nicht.
import { useBrowserLocation } from "wouter/use-browser-location" -ermöglicht es, den aktuellen Standort in der Adressleiste des Browsers zu manipulieren, eine winzige Wrapper um die Historie-API.import { useHashLocation } from "wouter/use-hash-location" -erhält in ähnlicher Weise den Standort aus dem Hash-Teil der Adresse, dh der Zeichenfolge nach einer # .import { memoryLocation } from "wouter/memory-location" -Ein Memory-Ort-Haken mit Historieunterstützung, externer Navigation und unveränderlicher Modus zum Testen. Beachten Sie den Modulnamen, da es sich um einen hohen Reihenhaken handelt. Sehen Sie, wie der Speicherort für das Testen verwendet werden kann.Routing -Haken
Importieren vom wouter -Modul.
useRoute - Zeigt an, ob die aktuelle Seite dem angegebenen Muster übereinstimmt oder nicht.useLocation - Ermöglicht die Manipulation des aktuellen Standorts des Routers standardmäßig für den Browser -Standort. HINWEIS: Dies ist nicht dasselbe wie bei useBrowserLocation , lesen Sie unten.useParams - Gibt ein Objekt mit Parametern zurück, die von der nächsten Route übereinstimmen.useSearch - gibt eine Suchzeichenfolge zurück - alles, was nach dem nachgeht ? .useRouter - Gibt ein globales Router -Objekt zurück, das die Konfiguration hält. Verwenden Sie es nur, wenn Sie das Routing anpassen möchten.Komponenten
Importieren vom wouter -Modul.
<Route /> - rendern eine Komponente, die auf einem Muster basiert.<Link /> - Wraps <a> ermöglicht es, eine Navigation durchzuführen.<Switch /> - exklusives Routing, nur die erste übereinstimmende Route.<Redirect /> - Wenn er gerendert wird, führt er eine sofortige Navigation durch.<Router /> -Eine optionale Komponente der optionalen Konfiguration auf der erweiterten Routing. useRoute : Routenübereinstimmung und Parameter Überprüft, ob der aktuelle Speicherort dem angegebenen Muster übereinstimmt, und ein Objekt mit Parametern zurückgibt. Dies wird von einer wunderbaren regexparam -Bibliothek angetrieben, sodass alle Mustersyntax vollständig unterstützt werden.
Sie können useRoute verwenden, um manuelles Routing durchzuführen oder benutzerdefinierte Logik wie Routenübergänge usw. zu implementieren.
import { useRoute } from "wouter" ;
const Users = ( ) => {
// `match` is a boolean
const [ match , params ] = useRoute ( "/users/:name" ) ;
if ( match ) {
return < > Hello, { params . name } ! </ > ;
} else {
return null ;
}
} ;Ein kurzes Cheatsblatt, welche Arten von Segmenten unterstützt werden:
useRoute ( "/app/:page" ) ;
useRoute ( "/app/:page/:section" ) ;
// optional parameter, matches "/en/home" and "/home"
useRoute ( "/:locale?/home" ) ;
// suffixes
useRoute ( "/movies/:title.(mp4|mov)" ) ;
// wildcards, matches "/app", "/app-1", "/app/home"
useRoute ( "/app*" ) ;
// optional wildcards, matches "/orders", "/orders/"
// and "/orders/completed/list"
useRoute ( "/orders/*?" ) ;
// regex for matching complex patterns,
// matches "/hello:123"
useRoute ( / ^[/]([a-z]+):([0-9]+)[/]?$ / ) ;
// and with named capture groups
useRoute ( / ^[/](?<word>[a-z]+):(?<num>[0-9]+)[/]?$ / ) ; Das zweite Element in den params ist ein Objekt mit Parametern oder Null, wenn es keine Übereinstimmung gab. Für Wildcard -Segmente lautet der Parametername "*" :
// wildcards, matches "/app", "/app-1", "/app/home"
const [ match , params ] = useRoute ( "/app*" ) ;
if ( match ) {
// "/home" for "/app/home"
const page = params [ "*" ] ;
}useLocation : Mit der Geschichte arbeiten Um den aktuellen Pfad zu erhalten und zwischen Seiten zu navigieren, rufen Sie den useLocation -Hook an. Ähnlich wie bei useState gibt es einen Wert und einen Setter: Die Komponente wird erneut rendern, wenn sich der Speicherort ändert, und durch das Aufrufen navigate können Sie diesen Wert aktualisieren und die Navigation ausführen.
Standardmäßig werden die useBrowserLocation unter der Haube verwendet. Sie können dies jedoch in einer Router Komponente auf der obersten Ebene konfigurieren (beispielsweise, wenn Sie sich irgendwann zum Wechsel zu einem Hash-basierten Routing entscheiden). useLocation gibt auch einen Scoped -Pfad zurück, wenn sie in verschachtelten Routen oder mit der Einstellung des Basispfads verwendet werden.
import { useLocation } from "wouter" ;
const CurrentLocation = ( ) => {
const [ location , navigate ] = useLocation ( ) ;
return (
< div >
{ `The current page is: ${ location } ` }
< a onClick = { ( ) => navigate ( "/somewhere" ) } > Click to update </ a >
</ div >
) ;
} ; Alle Komponenten rufen intern den useLocation -Hook auf.
Die Setzermethode der useLocation kann auch ein optionales Objekt mit Parametern akzeptieren, um zu steuern, wie das Navigationsaktualisierung stattfindet.
Wenn der Browser -Standort verwendet wird (Standard), akzeptiert useLocation Hook replace Flag, um den Haken zu fordern, den aktuellen Verlaufseintrag zu ändern, anstatt eine neue hinzuzufügen. Es ist das gleiche wie das Aufrufen replaceState .
const [ location , navigate ] = useLocation ( ) ;
navigate ( "/jobs" ) ; // `pushState` is used
navigate ( "/home" , { replace : true } ) ; // `replaceState` is used Darüber hinaus können Sie eine state Option zur Aktualisierung history.state anbieten.
navigate ( "/home" , { state : { modal : "promo" } } ) ;
history . state ; // { modal: "promo" } Standardmäßig verwendet Wouters useLocation Hook, mit dem die Navigation über useBrowserLocation pushState und replaceState .
Um dies anzupassen, wickeln Sie Ihre App in eine Router ein:
import { Router , Route } from "wouter" ;
import { useHashLocation } from "wouter/use-hash-location" ;
const App = ( ) => (
< Router hook = { useHashLocation } >
< Route path = "/about" component = { About } />
...
</ Router >
) ; Da diese Hooks Return -Werte haben, die useState ähnlich sind, ist es einfach und macht Spaß, Ihre eigenen Standorthaken zu erstellen: useCrossTabLocation , useLocalStorage , useMicroFrontendLocation und welche Routing -Logik, die Sie in der App unterstützen möchten. Probieren Sie es aus!
useParams : Extrahieren übereinstimmter Parameter Mit diesem Haken können Sie auf die Parameter zugreifen, die durch übereinstimmende dynamische Segmente ausgesetzt sind. Intern haben wir Ihre Komponenten einfach in einen Kontextanbieter ein, damit Sie auf diese Daten in der Route zugreifen können.
Auf diese Weise können Sie "Prop -Bohrungen" vermeiden, wenn Sie sich mit tief verschachtelten Komponenten innerhalb der Route befassen. HINWEIS: useParams extrahieren nur Parameter aus der nächstgelegenen übergeordneten Route.
import { Route , useParams } from "wouter" ;
const User = ( ) => {
const params = useParams ( ) ;
params . id ; // "1"
// alternatively, use the index to access the prop
params [ 0 ] ; // "1"
} ;
< Route path = "/user/:id" component = { User } > / >Es ist für Regex -Pfade gleich. Erfassungsgruppen können mit ihrem Index zugegriffen werden oder wenn es eine benannte Capture -Gruppe gibt, die stattdessen verwendet werden kann.
import { Route , useParams } from "wouter" ;
const User = ( ) => {
const params = useParams ( ) ;
params . id ; // "1"
params [ 0 ] ; // "1"
} ;
< Route path = { / ^[/]user[/](?<id>[0-9]+)[/]?$ / } component = { User } > / >useSearch : Abfragen von Zeichenfolgen Verwenden Sie diesen Haken, um den aktuellen Such -String -Wert (Abfrage) zu erhalten. Dies führt dazu, dass Ihre Komponente nur dann erneut rendert, wenn die Zeichenfolge selbst und nicht die vollständigen Standortaktualisierungen. Die zurückgegebene Suchzeichenfolge enthält keine ? Charakter.
import { useSearch } from "wouter" ;
// returns "tab=settings&id=1"
// the hook for extracting search parameters is coming soon!
const searchString = useSearch ( ) ; Verwenden Sie für die SSR ssrSearch -Requisite an den Router.
< Router ssrSearch = { request . search } > { /* SSR! */ } </ Router >Weitere Informationen zu Rendern und Flüssigkeitszufuhr finden Sie im Server-Side-Rendering.
useRouter : Zugriff auf das Router -Objekt Wenn Sie eine erweiterte Integration erstellen, beispielsweise benutzerdefinierte Standort -Hook, möchten Sie möglicherweise Zugriff auf das globale Router -Objekt erhalten. Router ist ein einfaches Objekt, das Routing -Optionen enthält, die Sie in der Router konfigurieren.
import { useRouter } from "wouter" ;
const Custom = ( ) => {
const router = useRouter ( ) ;
router . hook ; // `useBrowserLocation` by default
router . base ; // "/app"
} ;
const App = ( ) => (
< Router base = "/app" >
< Custom />
</ Router >
) ; <Route path={pattern} /> Route repräsentiert ein Stück der App, das basierend auf einem path bedingt erzeugt wird. Muster hat die gleiche Syntax wie das Argument, das Sie an useRoute übergeben.
Die Bibliothek bietet mehrere Möglichkeiten, um den Körper einer Route zu deklarieren:
import { Route } from "wouter" ;
// simple form
< Route path = "/home" > < Home /> </ Route >
// render-prop style
< Route path = "/users/:id" >
{ params => < UserPage id = { params . id } /> }
</ Route >
// the `params` prop will be passed down to <Orders />
< Route path = "/orders/:status" component = { Orders } /> Es wird angenommen, dass eine Route ohne Pfad immer übereinstimmt, und er ist der gleiche wie <Route path="*" /> . Verwenden Sie diesen Trick bei der Entwicklung Ihrer App, um den Inhalt der Route ohne Navigation zu sehen.
- <Route path="/some/page">
+ <Route>
{/* Strip out the `path` to make this visible */}
</Route> Das Nisting ist ein Kernmerkmal des Wouters und kann über die nest -Propie auf einer Route aktiviert werden. Wenn diese Requisite vorhanden ist, entspricht die Route mit allem, was mit einem bestimmten Muster beginnt, und erstellt einen verschachtelten Routing -Kontext. Alle Kinderwege erhalten einen Ort in Bezug auf dieses Muster.
Schauen wir uns dieses Beispiel an:
< Route path = "/app" nest >
< Route path = "/users/:id" nest >
< Route path = "/orders" />
</ Route >
</ Route > Diese erste Route ist für alle Pfade aktiv, die mit /app beginnen. Dies entspricht einem Basispfad in Ihrer App.
Der zweite verwendet dynamisches Muster, um Pfade wie /app/user/1 , /app/user/1/anything und so weiter zu entsprechen.
Schließlich funktioniert die innerste Route nur für Pfade, die wie /app/users/1/orders aussehen. Das Match ist streng, da diese Route keine nest -Requisite hat und wie gewohnt funktioniert.
Wenn Sie useLocation() innerhalb der letzten Route anrufen, werden /orders und nicht /app/users/1/orders zurückgegeben. Dies schafft eine schöne Isolation und erleichtert die Änderung der Elternroute, ohne sich Sorgen zu machen, dass der Rest der App nicht mehr funktioniert. Wenn Sie jedoch zu einer Seite der obersten Ebene navigieren müssen, können Sie ein Präfix ~ verwenden, um auf einen absoluten Pfad zu verweisen:
< Route path = "/payments" nest >
< Route path = "/all" >
< Link to = "~/home" > Back to Home </ Link >
</ Route >
</ Route > Hinweis: Die nest -Prop ändert die Regex nicht in Regex -Pfade. Stattdessen bestimmt die nest -Prop nur, ob verschachtelte Routen mit dem Rest des Pfades oder demselben Pfad übereinstimmen. Verwenden Sie ein Regex -Muster wie /^[/](your pattern)[/]?$/ Verwenden Sie ein Regex -Muster wie /^[/](your pattern)(?=$|[/])/ (Dies entspricht entweder mit dem Ende der Zeichenfolge oder einem Schrägstrich für zukünftige Segmente) ein Regex -Muster wie/^[/] (Ihr Muster).
<Link href={path} /> Die Linkkomponente rendert ein <a /> Element, das beim Klicken eine Navigation durchführt.
import { Link } from "wouter"
< Link href = "/" > Home </ Link >
// `to` is an alias for `href`
< Link to = "/" > Home < / Link>
// all standard `a` props are proxied
< Link href = "/" className = "link" aria-label = "Go to homepage" > Home </ Link >
// all location hook options are supported
< Link href = "/" replace state = { { animate : true } } / > Link wird seine Kinder immer in ein <a /> -Tags einwickeln, es sei denn, asChild Prop ist bereitgestellt. Verwenden Sie dies, wenn Sie eine benutzerdefinierte Komponente benötigen, die eine <a /> unter der Motorhaube macht.
// use this instead
< Link to = "/" asChild >
< UIKitLink />
</ Link >
// Remember, `UIKitLink` must implement an `onClick` handler
// in order for navigation to work! Wenn Sie eine Funktion als className -Requisite übergeben, wird sie mit einem booleschen Wert aufgerufen, der angibt, ob die Verbindung für die aktuelle Route aktiv ist. Sie können dies verwenden, um aktive Links zu stylen (z. B. für Links im Navigationsmenü).
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav </ Link >Lesen Sie hier mehr über aktive Links.
<Switch /> Es gibt Fälle, in denen Sie eine exklusive Routing haben möchten: Um sicherzustellen, dass zu diesem Zeitpunkt nur eine Route gerendert wird, auch wenn sich die Routen überlappen. Das ist, was Switch tut: Er macht nur die erste passende Route .
import { Route , Switch } from "wouter" ;
< Switch >
< Route path = "/orders/all" component = { AllOrders } />
< Route path = "/orders/:status" component = { Orders } />
{ /*
in wouter, any Route with empty path is considered always active.
This can be used to achieve "default" route behaviour within Switch.
Note: the order matters! See examples below.
*/ }
< Route > This is rendered when nothing above has matched </ Route >
</ Switch > ; Wenn keine Route in Switch -Übereinstimmungen ist, wird die letzte leere Route als Fallback verwendet. Siehe Abschnitt FAQ- und Code -Rezepte, um sich über Standardrouten zu lesen.
<Redirect to={path} /> Wenn montiert wird, führt eine Weiterleitung zu einem bereitgestellten path durch. Verwendet useLocation Hook intern, um die Navigation innerhalb eines useEffect -Blocks auszulösen.
Redirect kann auch Requisiten zum Anpassen der Navigation akzeptieren, z. B. zum Festlegen des Verlaufszustands beim Navigieren. Diese Optionen sind spezifisch für den aktuell verwendeten Standorthaken.
< Redirect to = "/" />
// arbitrary state object
< Redirect to = "/" state = { { modal : true } } / >
// use `replaceState`
< Redirect to = "/" replace /> Wenn Sie beispielsweise eine fortgeschrittenere Logik für die Navigation benötigen, um die Umleitung innerhalb eines Ereignishandlers auszulösen, sollten Sie stattdessen die Verwendung useLocation Hook verwenden:
import { useLocation } from "wouter" ;
const [ location , setLocation ] = useLocation ( ) ;
fetchOrders ( ) . then ( ( orders ) => {
setOrders ( orders ) ;
setLocation ( "/app/orders" ) ;
} ) ;<Router hook={hook} parser={fn} base={basepath} hrefs={fn} />Im Gegensatz zum React-Router müssen Routen in Wouter nicht in eine Komponente auf der oberen Ebene eingewickelt werden . Ein internes Router-Objekt wird auf Anfrage konstruiert, sodass Sie Ihre App schreiben können, ohne sie mit einer Kaskade von Anbietern auf höchstem Niveau zu verschmutzen. Es gibt jedoch Fälle, in denen das Routing -Verhalten angepasst werden muss.
Zu diesen Fällen gehören Hash-basierte Routing, Basispath-Unterstützung, benutzerdefinierte Matcher-Funktion usw.
import { useHashLocation } from "wouter/use-hash-location" ;
< Router hook = { useHashLocation } base = "/app" >
{ /* Your app goes here */ }
</ Router > ; Ein Router ist ein einfaches Objekt, das die Routing -Konfigurationsoptionen enthält. Sie können dieses Objekt jederzeit mit einem useRouter -Haken erhalten. Die Liste der derzeit verfügbaren Optionen:
hook: () => [location: string, setLocation: fn] - ist eine React -Hook -Funktion, die sich den Standortänderungen abonniert. Es gibt ein Paar aktueller location -String -EG /app/users und eine setLocation -Funktion für die Navigation zurück. Sie können diesen Haken von jeder Komponente Ihrer App verwenden, indem Sie useLocation() Hook aufrufen. Siehe Anpassen des Standorthakens.
searchHook: () => [search: string, setSearch: fn] - Ähnlich wie bei hook , aber zum Erhalten der aktuellen Suchzeichenfolge.
base: string - Eine optionale Einstellung, mit der ein Basispfad wie /app angegeben werden kann. Alle Anwendungswege sind relativ zu diesem Weg. Um auf einen absoluten Weg zu navigieren, haben Sie Ihren Weg mit einem ~ . Siehe die FAQ.
parser: (path: string, loose?: boolean) => { pattern, keys } Erstellt ein Regexp für die Übereinstimmung mit dem aktuellen Speicherort mit den benutzerdefinierten Mustern wie /app/users/:id . Hat die gleiche Schnittstelle wie die parse -Funktion von regexparam . Siehe dieses Beispiel, das eine benutzerdefinierte Parser -Funktion demonstriert.
ssrPath: string und ssrSearch: string Verwenden Sie diese, wenn Sie Ihre App auf dem Server rendern.
hrefs: (href: boolean) => string - Eine Funktion zur Transformation von href -Attribut eines <a /> -Elements, das durch Link gerendert wird. Es wird verwendet, um das Hash-basierte Routing zu unterstützen. Standardmäßig ist href -Attribut das gleiche wie der href oder to einen Link . Ein Standorthaken kann auch eine Eigenschaft hook.hrefs definieren, in diesem Fall wird der href abgeleitet.
Du kannst! Wickeln Sie Ihre App mit <Router base="/app" /> Komponente, und das sollte den Trick ausführen:
import { Router , Route , Link } from "wouter" ;
const App = ( ) => (
< Router base = "/app" >
{ /* the link's href attribute will be "/app/users" */ }
< Link href = "/users" > Users </ Link >
< Route path = "/users" > The current path is /app/users! </ Route >
</ Router >
) ; Das Aufrufen von useLocation() innerhalb einer Route in einer App mit Basispfad gibt einen Pfad zurück, der an die Basis geschrieben ist. Das heißt, wenn Basis "/app" und Pathname "/app/users" ist, ist die zurückgegebene Zeichenfolge "/users" . Dementsprechend findet das Aufrufen navigate die Basis automatisch an das Pfadargument für Sie an.
Wenn Sie mehrere verschachtelte Router haben, werden Basiswege geerbt und stapeln.
< Router base = "/app" >
< Router base = "/cms" >
< Route path = "/users" > Path is /app/cms/users! </ Route >
</ Router >
</ Router > Eines der gängigen Muster in der Anwendungsrouting ist eine Standardroute, die als Fallback angezeigt wird, falls keine andere Route übereinstimmt (z. B. wenn Sie die Nachricht übernehmen müssen). In Wouter kann dies leicht als Kombination aus <Switch /> -Komponente und einer Standardroute erfolgen:
import { Switch , Route } from "wouter" ;
< Switch >
< Route path = "/about" > ... </ Route >
< Route > 404, Not Found! </ Route >
</ Switch > ;HINWEIS: Die Reihenfolge der Switch Children -Angelegenheiten, die Standardroute sollte immer zuletzt sein.
Wenn Sie Zugriff auf das übereinstimmende Segment des Pfades haben möchten, können Sie Wildcard -Parameter verwenden:
< Switch >
< Route path = "/users" > ... </ Route >
{ /* will match anything that starts with /users/, e.g. /users/foo, /users/1/edit etc. */ }
< Route path = "/users/*" > ... </ Route >
{ /* will match everything else */ }
< Route path = "*" >
{ ( params ) => `404, Sorry the page ${ params [ "*" ] } does not exist!` }
</ Route >
</ Switch >▶ Demo Sandbox
Geben Sie anstelle einer regulären className -Zeichenfolge eine Funktion zur Verwendung einer benutzerdefinierten Klasse an, wenn dieser Link mit der aktuellen Route übereinstimmt. Beachten Sie, dass es immer eine genaue Übereinstimmung durchführt (dh /users sind nicht aktiv für /users/1 ).
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav link </ Link > Wenn Sie andere Requisiten steuern müssen, wie z. B. aria-current oder style , können Sie Ihren eigenen <Link /> -Wrapper schreiben und feststellen, ob der Pfad mit dem useRoute Hook aktiv ist.
const [ isActive ] = useRoute ( props . href ) ;
return (
< Link { ... props } asChild >
< a style = { isActive ? { color : "red" } : { } } > { props . children } </ a >
</ Link >
) ;▶ Demo Sandbox
Wenn ein nachverfolgender Schrägstrich für das Routing Ihrer App wichtig ist, können Sie einen benutzerdefinierten Parser angeben. Parser ist eine Methode, die eine Musterzeichenfolge annimmt und einen Regexp und ein Array von Parsen -Schlüssel zurückgibt. Es verwendet die Signatur einer parse von regexparam .
Schreiben wir einen benutzerdefinierten Parser, der auf einem beliebten path-to-regexp Paket basiert, das die Option Strict Routen unterstützt.
import { pathToRegexp } from "path-to-regexp" ;
/**
* Custom parser based on `pathToRegexp` with strict route option
*/
const strictParser = ( path , loose ) => {
const keys = [ ] ;
const pattern = pathToRegexp ( path , keys , { strict : true , end : ! loose } ) ;
return {
pattern ,
// `pathToRegexp` returns some metadata about the keys,
// we want to strip it to just an array of keys
keys : keys . map ( ( k ) => k . name ) ,
} ;
} ;
const App = ( ) => (
< Router parser = { strictParser } >
< Route path = "/foo" > ... </ Route >
< Route path = "/foo/" > ... </ Route >
</ Router >
) ;▶ Demo Sandbox
Ja! Jede Route mit dem vorhandenen nest -Prop erzeugt einen Nestkontext. Denken Sie daran, dass der Ort in einer verschachtelten Route geschrieben wird.
const App = ( ) => (
< Router base = "/app" >
< Route path = "/dashboard" nest >
{ /* the href is "/app/dashboard/users" */ }
< Link to = "/users" />
< Route path = "/users" >
{ /* Here `useLocation()` returns "/users"! */ }
</ Route >
</ Route >
</ Router >
) ;▶ Demo Sandbox
Ja, die navigate -Funktion wird aus dem Modul "wouter/use-browser-location" ausgesetzt:
import { navigate } from "wouter/use-browser-location" ;
navigate ( "/" , { replace : true } ) ;Es ist die gleiche Funktion, die intern verwendet wird.
Ja! Obwohl das Projekt nicht in TypeScript geschrieben ist, werden die Typ -Definitionsdateien mit dem Paket gebündelt.
Schauen wir uns an, wie Wouter-Routen mit framer-motion animiert werden können. Animieren von Eingabetrümpfen sind einfach, aber die Übergänge der Exits erfordern ein bisschen mehr Arbeit. Wir werden die AnimatePresence -Komponente verwenden, die die Seite im DOM aufbewahrt, bis die Exit -Animation abgeschlossen ist.
Leider animiert AnimatePresence nur seine direkten Kinder , sodass dies nicht funktioniert:
import { motion , AnimatePresence } from "framer-motion" ;
export const MyComponent = ( ) => (
< AnimatePresence >
{ /* This will not work! `motion.div` is not a direct child */ }
< Route path = "/" >
< motion . div
initial = { { opacity : 0 } }
animate = { { opacity : 1 } }
exit = { { opacity : 0 } }
/>
</ Route >
</ AnimatePresence >
) ; Die Problemumgehung soll diese Route manuell mit useRoute übereinstimmen:
export const MyComponent = ( { isVisible } ) => {
const [ isMatch ] = useRoute ( "/" ) ;
return (
< AnimatePresence >
{ isMatch && (
< motion . div
initial = { { opacity : 0 } }
animate = { { opacity : 1 } }
exit = { { opacity : 0 } }
/>
) }
</ AnimatePresence >
) ;
} ; Komplexere Beispiele sind die Verwendung von useRoutes Hook (ähnlich wie React Router), aber Wouter versendet es nicht außerhalb des Boxs. Bitte beachten Sie dieses Problem für die Problemumgehung.
Preact-Exporte sind über ein separates Paket mit dem Namen wouter-preact (oder im wouter/preact Namespace erhältlich, diese Methode ist jedoch nicht empfohlen, da React als Peer-Abhängigkeit erforderlich ist):
- import { useRoute, Route, Switch } from "wouter";
+ import { useRoute, Route, Switch } from "wouter-preact";Möglicherweise müssen Sie sicherstellen, dass Sie die neueste Version von Preact X mit Unterstützung für Hooks haben.
▶ Demo Sandbox
Um Ihre App auf dem Server zu rendern, müssen Sie Ihre App mit einem Router auf höchstem Niveau einwickeln und ssrPath Requisit angeben (normalerweise abgeleitet von der aktuellen Anforderung). Optional akzeptiert Router ssrSearch -Parameter, falls er Zugriff auf eine Suchzeichenfolge auf einem Server haben muss.
import { renderToString } from "react-dom/server" ;
import { Router } from "wouter" ;
const handleRequest = ( req , res ) => {
// top-level Router is mandatory in SSR mode
const prerendered = renderToString (
< Router ssrPath = { req . path } ssrSearch = { req . search } >
< App />
</ Router >
) ;
// respond with prerendered html
} ; TIPP: Wouter kann ssrSearch vorab füllen, wenn ssrPath das enthält ? Charakter. Diese sind also gleichwertig:
< Router ssrPath = "/goods?sort=asc" /> ;
// is the same as
< Router ssrPath = "/goods" ssrSearch = "sort=asc" /> ; Auf dem Client muss das statische Markup hydratisiert werden, damit Ihre App interaktiv wird. Beachten Sie, dass der auf dem Client gerenderte JSX -Warnungen mit dem vom Server verwendeten JSX mit dem von dem Server verwendeten JSX übereinstimmen muss. Daher muss die Router vorhanden sein.
import { hydrateRoot } from "react-dom/client" ;
const root = hydrateRoot (
domNode ,
// during hydration, `ssrPath` is set to `location.pathname`,
// `ssrSearch` set to `location.search` accordingly
// so there is no need to explicitly specify them
< Router >
< App />
</ Router >
) ;▶ Demo
Das Testen mit Wouter unterscheidet sich nicht vom Testen regelmäßiger React -Apps. Sie benötigen häufig eine Möglichkeit, eine Leuchte für den aktuellen Standort zu liefern, um eine bestimmte Route zu rendern. Dies kann leicht durchgeführt werden, indem Sie den normalen Standorthaken mit memoryLocation austauschen. Es ist eine Initialisiererfunktion, die einen Haken zurückgibt, den Sie dann in einem Router auf oberster Ebene angeben können.
import { render } from "@testing-library/react" ;
import { memoryLocation } from "wouter/memory-location" ;
it ( "renders a user page" , ( ) => {
// `static` option makes it immutable
// even if you call `navigate` somewhere in the app location won't change
const { hook } = memoryLocation ( { path : "/user/2" , static : true } ) ;
const { container } = render (
< Router hook = { hook } >
< Route path = "/user/:id" > { ( params ) => < > User ID: { params . id } </ > } </ Route >
</ Router >
) ;
expect ( container . innerHTML ) . toBe ( "User ID: 2" ) ;
} ) ; Der Haken kann so konfiguriert werden, dass der Navigationsverlauf aufzeichnet. Zusätzlich wird eine navigate für die externe Navigation geliefert.
it ( "performs a redirect" , ( ) => {
const { hook , history , navigate } = memoryLocation ( {
path : "/" ,
// will store navigation history in `history`
record : true ,
} ) ;
const { container } = render (
< Router hook = { hook } >
< Switch >
< Route path = "/" > Index </ Route >
< Route path = "/orders" > Orders </ Route >
< Route >
< Redirect to = "/orders" />
</ Route >
</ Switch >
</ Router >
) ;
expect ( history ) . toStrictEqual ( [ "/" ] ) ;
navigate ( "/unknown/route" ) ;
expect ( container . innerHTML ) . toBe ( "Orders" ) ;
expect ( history ) . toStrictEqual ( [ "/" , "/unknown/route" , "/orders" ] ) ;
} ) ; Wir haben einige tolle Neuigkeiten für Sie! Wenn Sie ein minimalistischer Bündel-Nomad sind und einen verdammt einfachen Routing in Ihrer App benötigen, können Sie nur Haken mit nackten Standort verwenden. Zum Beispiel useBrowserLocation -Hook, der nur 650 Bytes gzipiert ist, und manuell mit dem aktuellen Ort übereinstimmen:
import { useBrowserLocation } from "wouter/use-browser-location" ;
const UsersRoute = ( ) => {
const [ location ] = useBrowserLocation ( ) ;
if ( location !== "/users" ) return null ;
// render the route
} ;Wouters Motto ist "minimalistisch-freundlich" .
Wouter -Illustrationen und Logos wurden von Katya Simacheva und Katya Vakulenko gemacht. Vielen Dank an @jeetiss und all die erstaunlichen Mitwirkenden für die Unterstützung bei der Entwicklung.