️ Ces documents sont réservés à Wouter V3. Veuillez trouver la documentation pour [email protected] ici
<Router /> , il est entièrement facultatif .Route , Link , Switch et Redirect .useLocation , useRoute et useRouter . ... J'adore Wouter. Il est minuscule, embrasse pleinement les crochets et possède une API intuitive et nue. Je peux accomplir tout ce que je pouvais avec React-Router avec Wouter, et cela semble plus minimaliste sans être gênant.
Matt Miller , un écosystème réactif exhaustif pour 2020
Wouter fournit une API simple que de nombreux développeurs et auteurs de bibliothèques apprécient. Quelques projets notables qui utilisent Wouter: Ultra , React-Three-Fibre , Sunmao UI , Million et bien d'autres.
Commencer
API Wouter
API Hooks
useRoute : correspondance d'itinéraire et paramètresuseLocation : Travailler avec l'histoireuseParams : extraire les paramètres correspondantsuseSearch : les chaînes de requêteuseRouter : Accès à l'objet du routeurAPI composant
<Route path={pattern} /><Link href={path} /><Switch /><Redirect to={path} /><Router hook={hook} parser={fn} base={basepath} />FAQ et recettes de code
Remerciements
Tout d'abord, ajoutez Wouter à votre projet.
npm i wouter Ou, si vous utilisez Preact, utilisez la commande suivante npm i wouter-preact .
Consultez cette application de démonstration simple ci-dessous. Il ne couvre pas les crochets et d'autres fonctionnalités telles que le routage imbriqué, mais c'est un bon point de départ pour ceux qui migrent du routeur React.
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 >
</ >
) ; Cette bibliothèque est conçue pour la compatibilité ES2020 + . Si vous devez prendre en charge les navigateurs plus anciens, assurez-vous de transpiler node_modules . De plus, la version TypeScript minimale prise en charge est 4.1 afin de prendre en charge l'inférence du paramètre de route.
Wouter est livré avec trois types d'API: les crochets d'emplacement autonome de bas niveau, les crochets pour le routage et la correspondance de motifs et une API basée sur des composants plus traditionnelle similaire à celle de React Router.
Vous êtes libre de choisir tout ce qui fonctionne pour vous: utilisez des crochets de localisation lorsque vous souhaitez garder votre application aussi petite que possible et n'avez pas besoin de correspondance de motifs; Utilisez des crochets de routage lorsque vous souhaitez créer des composants de routage personnalisés; Ou si vous construisez une application traditionnelle avec des pages et une navigation - les composants peuvent être utiles.
Consultez également la FAQ et les recettes de code pour des choses plus avancées comme les liens actifs, les itinéraires par défaut, le rendu côté serveur, etc.
Crochets de localisation
Ceux-ci peuvent être utilisés séparément du module principal et ont une interface similaire à useState . Ces crochets ne prennent pas en charge la nidification, le chemin de base, la correspondance des itinéraires.
import { useBrowserLocation } from "wouter/use-browser-location" - permet de manipuler l'emplacement actuel dans la barre d'adresse du navigateur, un minuscule wrapper autour de l'API History.import { useHashLocation } from "wouter/use-hash-location" - de même, obtient l'emplacement de la partie de hachage de l'adresse, c'est-à-dire la chaîne après un # .import { memoryLocation } from "wouter/memory-location" - un crochet d'emplacement en mémoire avec support historique, navigation externe et mode immuable pour les tests. Notez le nom du module car il s'agit d'un crochet d'ordre élevé. Découvrez comment l'emplacement de la mémoire peut être utilisé dans les tests.Crochets de routage
Importation du module wouter .
useRoute - montre si la page actuelle correspond ou non au modèle fourni.useLocation - Permet de manipuler l'emplacement du routeur actuel, par défaut, souscrit à l'emplacement du navigateur. Remarque: Ce n'est pas la même chose que useBrowserLocation , lisez ci-dessous.useParams - Renvoie un objet avec des paramètres correspondants à partir de l'itinéraire le plus proche.useSearch - Renvoie une chaîne de recherche - tout ce qui va après le ? .useRouter - Renvoie un objet de routeur global qui maintient la configuration. Utilisez-le uniquement si vous souhaitez personnaliser le routage.Composants
Importation du module wouter .
<Route /> - Rend conditionnellement un composant basé sur un modèle.<Link /> - wraps <a> , permet de permettre une navigation.<Switch /> - Le routage exclusif ne fait que le premier itinéraire correspondant.<Redirect /> - Une fois rendu, effectue une navigation immédiate.<Router /> - un composant de niveau supérieur en option pour la configuration de routage avancée. useRoute : correspondance d'itinéraire et paramètres Vérifie si l'emplacement actuel correspond au modèle fourni et renvoie un objet avec des paramètres. Ceci est alimenté par une merveilleuse bibliothèque regexparam , donc toute sa syntaxe de modèle est pleinement prise en charge.
Vous pouvez utiliser useRoute pour effectuer un routage manuel ou implémenter une logique personnalisée, tels que les transitions de route, etc.
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 ;
}
} ;Une feuille de triche rapide de quels types de segments sont pris en charge:
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]+)[/]?$ / ) ; Le deuxième élément des params de la paire est un objet avec des paramètres ou null s'il n'y avait pas de correspondance. Pour les segments génériques, le nom du paramètre est "*" :
// wildcards, matches "/app", "/app-1", "/app/home"
const [ match , params ] = useRoute ( "/app*" ) ;
if ( match ) {
// "/home" for "/app/home"
const page = params [ "*" ] ;
}useLocation : Travailler avec l'histoire Pour obtenir le chemin actuel et naviguer entre les pages, appelez le crochet useLocation . De façon similaire à useState , il renvoie une valeur et un secteur: le composant sera redéfini lorsque l'emplacement change et en appelant navigate vous pouvez mettre à jour cette valeur et effectuer une navigation.
Par défaut, il utilise useBrowserLocation sous le capot, bien que vous puissiez configurer cela dans un composant Router de niveau supérieur (par exemple, si vous décidez à un moment donné pour passer à un routage basé sur le hachage). useLocation renvoie également le chemin de lunette lorsqu'il est utilisé dans les routes imbriquées ou avec le paramètre de chemin de base.
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 >
) ;
} ; Tous les composants appellent en interne le crochet useLocation .
La méthode du secteur d' useLocation peut également accepter un objet facultatif avec des paramètres pour contrôler la façon dont la mise à jour de la navigation se produira.
Lorsque l'emplacement du navigateur est utilisé (par défaut), le crochet useLocation accepte replace l'indicateur pour dire au crochet pour modifier l'entrée historique actuelle au lieu d'en ajouter une nouvelle. C'est la même chose que d'appeler replaceState .
const [ location , navigate ] = useLocation ( ) ;
navigate ( "/jobs" ) ; // `pushState` is used
navigate ( "/home" , { replace : true } ) ; // `replaceState` is used De plus, vous pouvez fournir une option state pour mettre à jour history.state lors de la navigation:
navigate ( "/home" , { state : { modal : "promo" } } ) ;
history . state ; // { modal: "promo" } Par défaut, Wouter utilise le crochet useLocation qui réagit à pushState et replaceState la navigation via useBrowserLocation .
Pour personnaliser cela, enveloppez votre application dans un composant Router :
import { Router , Route } from "wouter" ;
import { useHashLocation } from "wouter/use-hash-location" ;
const App = ( ) => (
< Router hook = { useHashLocation } >
< Route path = "/about" component = { About } />
...
</ Router >
) ; Étant donné que ces crochets ont des valeurs de retour similaires à useState , il est facile et amusant de construire vos propres crochets d'emplacement: useCrossTabLocation , useLocalStorage , useMicroFrontendLocation et quelle que soit la logique de routage que vous souhaitez prendre en charge dans l'application. Essayez-le!
useParams : extraire les paramètres correspondants Ce crochet vous permet d'accéder aux paramètres exposés via des segments dynamiques correspondants. En interne, nous enroulons simplement vos composants dans un fournisseur de contexte vous permettant d'accéder à ces données n'importe où dans le composant d' Route .
Cela vous permet d'éviter le "forage des accessoires" lorsque vous traitez des composants profondément imbriqués dans l'itinéraire. Remarque: useParams ne fera que l'extraire des paramètres de l'itinéraire parent le plus proche.
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 } > / >C'est la même chose pour les chemins d'expulsion. Les groupes de capture sont accessibles par leur index, ou s'il existe un groupe de capture nommé, qui peut être utilisé à la place.
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 : les chaînes de requête Utilisez ce crochet pour obtenir la valeur de chaîne de recherche (requête) actuelle. Cela fera le renvoyer votre composant uniquement lorsque la chaîne elle-même et non les mises à jour de la localisation complète. La chaîne de recherche retournée ne contient pas un ? personnage.
import { useSearch } from "wouter" ;
// returns "tab=settings&id=1"
// the hook for extracting search parameters is coming soon!
const searchString = useSearch ( ) ; Pour le SSR, utilisez ssrSearch Prop transmis au routeur.
< Router ssrSearch = { request . search } > { /* SSR! */ } </ Router >Reportez-vous au rendu côté serveur pour plus d'informations sur le rendu et l'hydratation.
useRouter : Accès à l'objet du routeur Si vous créez une intégration avancée, par exemple le crochet d'emplacement personnalisé, vous voudrez peut-être accéder à l'objet de routeur global. Le routeur est un objet simple qui contient des options de routage que vous configurez dans le composant Router .
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ésente un morceau de l'application qui est rendu conditionnellement en fonction d'un path de motif. Le motif a la même syntaxe que l'argument que vous transmettez à useRoute .
La bibliothèque fournit plusieurs façons de déclarer le corps de l'itinéraire:
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 } /> Un itinéraire sans chemin est considéré comme correspondant toujours, et il est le même que <Route path="*" /> . Lorsque vous développez votre application, utilisez cette astuce pour jeter un œil au contenu de l'itinéraire sans navigation.
- <Route path="/some/page">
+ <Route>
{/* Strip out the `path` to make this visible */}
</Route> La nidification est une caractéristique centrale de Wouter et peut être activée sur un itinéraire via le nest Prop. Lorsque cet accessoire est présent, l'itinéraire correspond à tout ce qui commence par un modèle donné et il crée un contexte de routage imbriqué. Tous les routes enfants recevront l'emplacement par rapport à ce modèle.
Jetons un coup d'œil à cet exemple:
< Route path = "/app" nest >
< Route path = "/users/:id" nest >
< Route path = "/orders" />
</ Route >
</ Route > Ce premier itinéraire sera actif pour tous les chemins qui commencent par /app , ce qui équivaut à avoir un chemin de base dans votre application.
Le second utilise un modèle dynamique pour faire correspondre les chemins comme /app/user/1 , /app/user/1/anything et ainsi de suite.
Enfin, l'itinéraire le plus intérieur ne fonctionnera que pour des chemins qui ressemblent à /app/users/1/orders . Le match est strict, car cet itinéraire n'a pas d'hélice nest et fonctionne comme d'habitude.
Si vous appelez useLocation() à l'intérieur du dernier itinéraire, il retournera /orders et non /app/users/1/orders . Cela crée une belle isolement et il est plus facile d'apporter des modifications à l'itinéraire des parents sans se soucier que le reste de l'application cesse de fonctionner. Cependant, si vous avez besoin de naviguer vers une page de niveau supérieur, vous pouvez utiliser un préfixe ~ pour vous référer à un chemin absolu:
< Route path = "/payments" nest >
< Route path = "/all" >
< Link to = "~/home" > Back to Home </ Link >
</ Route >
</ Route > Remarque: Le nest Prop ne modifie pas le regex transmis dans les chemins regex. Au lieu de cela, le nest Prop ne déterminera que si les routes imbriquées correspondront au reste du chemin ou au même chemin. Pour faire un chemin strict Regex, utilisez un motif regex comme /^[/](your pattern)[/]?$/ (Cela correspond à une obtenue en option et à la fin de la chaîne). Pour faire un regex niche, utilisez un motif regex comme /^[/](your pattern)(?=$|[/])/ (Cela correspond à l'extrémité de la chaîne ou à une barre oblique pour les futurs segments).
<Link href={path} /> Le composant de lien rend un élément <a /> qui, lorsqu'il est cliqué, effectue une navigation.
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 } } / > Le lien enveloppera toujours ses enfants dans une balise <a /> , à moins que l'hélice asChild ne soit fournie. Utilisez-le lorsque vous avez besoin d'avoir un composant personnalisé qui rend un <a /> sous le capot.
// use this instead
< Link to = "/" asChild >
< UIKitLink />
</ Link >
// Remember, `UIKitLink` must implement an `onClick` handler
// in order for navigation to work! Lorsque vous passez une fonction en tant que plongeon className , elle sera appelée avec une valeur booléenne indiquant si le lien est actif pour l'itinéraire actuel. Vous pouvez l'utiliser pour styliser des liens actifs (par exemple pour les liens dans le menu de navigation)
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav </ Link >En savoir plus sur les liens actifs ici.
<Switch /> Il y a des cas où vous voulez avoir un routage exclusif: pour vous assurer qu'un seul itinéraire est rendu à l'époque, même si les itinéraires ont des modèles qui se chevauchent. C'est ce que fait Switch : il ne fait que le premier itinéraire correspondant .
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 > ; Lorsqu'aucune route dans le commutateur ne correspond, le dernier Route vide sera utilisé comme repli. Voir la section FAQ et Code Recipes pour lire sur les itinéraires par défaut.
<Redirect to={path} /> Lorsque monté effectue une redirection vers un path fourni. Utilise le crochet useLocation en interne pour déclencher la navigation à l'intérieur d'un bloc useEffect .
Redirect peut également accepter les accessoires pour personnaliser la façon dont la navigation sera effectuée, par exemple pour définir l'état de l'historique lors de la navigation. Ces options sont spécifiques au crochet de localisation actuellement utilisé.
< Redirect to = "/" />
// arbitrary state object
< Redirect to = "/" state = { { modal : true } } / >
// use `replaceState`
< Redirect to = "/" replace /> Si vous avez besoin d'une logique plus avancée pour la navigation, par exemple, pour déclencher la redirection à l'intérieur d'un gestionnaire d'événements, envisagez d'utiliser useLocation Hook à la place:
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} />Contrairement au routeur React , les routes de Wouter n'ont pas à être enveloppées dans un composant de niveau supérieur . Un objet de routeur interne sera construit à la demande, vous pouvez donc commencer à écrire votre application sans le polluer avec une cascade de fournisseurs de haut niveau. Il y a cependant des cas, lorsque le comportement de routage doit être personnalisé.
Ces cas incluent le routage basé sur le hachage, le support de base de base, la fonction de correspondance personnalisée, etc.
import { useHashLocation } from "wouter/use-hash-location" ;
< Router hook = { useHashLocation } base = "/app" >
{ /* Your app goes here */ }
</ Router > ; Un routeur est un objet simple qui contient les options de configuration de routage. Vous pouvez toujours obtenir cet objet à l'aide d'un crochet useRouter . La liste des options actuellement disponibles:
hook: () => [location: string, setLocation: fn] - est une fonction React Hook qui souscrit aux modifications de localisation. Il renvoie une paire de chaînes location actuelles, par exemple /app/users et une fonction setLocation pour la navigation. Vous pouvez utiliser ce crochet à partir de n'importe quel composant de votre application en appelant useLocation() Hook. Voir Personnalisation du crochet d'emplacement.
searchHook: () => [search: string, setSearch: fn] - similaire à hook , mais pour obtenir la chaîne de recherche actuelle.
base: string - Un paramètre facultatif qui permet de spécifier un chemin de base, tel que /app . Tous les voies d'application seront relatives à ce chemin. Pour naviguer vers un chemin absolu, préfixez votre chemin avec un ~ . Voir la FAQ.
parser: (path: string, loose?: boolean) => { pattern, keys } - une fonction d'analyse de motif. Produit un regexp pour faire correspondre l'emplacement actuel par rapport aux modèles définis par l'utilisateur comme /app/users/:id . A la même interface que la fonction parse de regexparam . Voir cet exemple qui montre la fonction de l'analyseur personnalisé.
ssrPath: string et ssrSearch: string les utilise lorsque vous rendez votre application sur le serveur.
hrefs: (href: boolean) => string - Une fonction de transformation de l'attribut href d'un élément <a /> rendu par Link . Il est utilisé pour prendre en charge le routage basé sur le hachage. Par défaut, l'attribut href est le même que le href ou to propage d'un Link . Un crochet d'emplacement peut également définir une propriété hook.hrefs , dans ce cas, le href sera déduit.
Tu peux! Enveloppez votre application avec le composant <Router base="/app" /> et cela devrait faire l'affaire:
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 >
) ; L'appel useLocation() dans un itinéraire dans une application avec chemin de base renverra un chemin à portée de main vers la base. Ce qui signifie que lorsque la base est "/app" et que pathname est "/app/users" La chaîne retournée est "/users" . En conséquence, l'appel navigate ajoutera automatiquement la base à l'argument de chemin pour vous.
Lorsque vous avez plusieurs routeurs imbriqués, les chemins de base sont hérités et empilés.
< Router base = "/app" >
< Router base = "/cms" >
< Route path = "/users" > Path is /app/cms/users! </ Route >
</ Router >
</ Router > L'un des modèles communs dans le routage des applications est d'avoir un itinéraire par défaut qui sera affiché comme une secours, au cas où aucune autre route ne correspond (par exemple, si vous avez besoin de rendre un message 404). Dans Wouter, cela peut facilement être fait en tant que combinaison de composant <Switch /> et une route par défaut:
import { Switch , Route } from "wouter" ;
< Switch >
< Route path = "/about" > ... </ Route >
< Route > 404, Not Found! </ Route >
</ Switch > ;Remarque: L'ordre des enfants de commutation est important, la route par défaut doit toujours passer en dernier.
Si vous souhaitez avoir accès au segment apparié du chemin, vous pouvez utiliser les paramètres de jogne:
< 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
Au lieu d'une chaîne className régulière, fournissez une fonction pour utiliser la classe personnalisée lorsque ce lien correspond à l'itinéraire actuel. Notez qu'il effectuera toujours une correspondance exacte (c'est-à-dire /users ne seront pas actifs pour /users/1 ).
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav link </ Link > Si vous avez besoin de contrôler d'autres accessoires, tels que aria-current ou style , vous pouvez écrire votre propre wrapper <Link /> et détecter si le chemin est actif en utilisant le crochet useRoute .
const [ isActive ] = useRoute ( props . href ) ;
return (
< Link { ... props } asChild >
< a style = { isActive ? { color : "red" } : { } } > { props . children } </ a >
</ Link >
) ;▶ Demo Sandbox
Si une barre oblique de fuite est importante pour le routage de votre application, vous pouvez spécifier un analyseur personnalisé. Parser est une méthode qui prend une chaîne de modèle et renvoie un regexp et un tableau de clé analysée. Il utilise la signature d'une fonction parse de regexparam .
Écrivons un analyseur personnalisé basé sur un package path-to-regexp populaire qui prend en charge l'option Stricte Routes.
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
Oui! Toute route avec nest Prop présente crée un contexte de nidification. Gardez à l'esprit que l'emplacement à l'intérieur d'un itinéraire imbriqué sera portée.
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
Oui, la fonction navigate est exposée à partir du module "wouter/use-browser-location" :
import { navigate } from "wouter/use-browser-location" ;
navigate ( "/" , { replace : true } ) ;C'est la même fonction qui est utilisée en interne.
Oui! Bien que le projet ne soit pas rédigé en TypeScript, les fichiers de définition de type sont regroupés avec le package.
Voyons comment les routes de Wouter peuvent être animées avec framer-motion . L'animation des transitions ENTER est facile, mais les transitions de sortie nécessitent un peu plus de travail. Nous utiliserons le composant AnimatePresence qui gardera la page dans le DOM jusqu'à ce que l'animation de sortie soit terminée.
Malheureusement, AnimatePresence anime uniquement ses enfants directs , donc cela ne fonctionnera pas:
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 >
) ; La solution de contournement est de faire correspondre cette voie manuellement avec useRoute :
export const MyComponent = ( { isVisible } ) => {
const [ isMatch ] = useRoute ( "/" ) ;
return (
< AnimatePresence >
{ isMatch && (
< motion . div
initial = { { opacity : 0 } }
animate = { { opacity : 1 } }
exit = { { opacity : 0 } }
/>
) }
</ AnimatePresence >
) ;
} ; Des exemples plus complexes impliquent d'utiliser useRoutes Hook (similaire à la façon dont le routeur React le fait), mais Wouter ne l'expédie pas à l'extérieur de la boîte. Veuillez vous référer à ce problème pour la solution de contournement.
Les exportations de préact sont disponibles via un package séparé nommé wouter-preact (ou dans l'espace de noms wouter/preact , mais cette méthode n'est pas recommandée car elle nécessite une réaction en tant que dépendance des pairs):
- import { useRoute, Route, Switch } from "wouter";
+ import { useRoute, Route, Switch } from "wouter-preact";Vous devrez peut-être vous assurer que vous disposez de la dernière version de Preact X avec la prise en charge des crochets.
▶ Demo Sandbox
Afin de rendre votre application sur le serveur, vous devrez envelopper votre application avec un routeur de niveau supérieur et spécifier ssrPath PROP (généralement dérivé de la demande actuelle). Facultativement, Router accepte le paramètre ssrSearch si besoin d'avoir accès à une chaîne de recherche sur un serveur.
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
} ; Astuce: Wouter peut pré-remplir ssrSearch , si ssrPath contient le ? personnage. Ce sont donc équivalents:
< Router ssrPath = "/goods?sort=asc" /> ;
// is the same as
< Router ssrPath = "/goods" ssrSearch = "sort=asc" /> ; Sur le client, le balisage statique doit être hydraté pour que votre application devienne interactive. Notez que pour éviter les avertissements d'hydratation, le JSX rendu sur le client doit correspondre à celui utilisé par le serveur, de sorte que le composant Router doit être présent.
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 >
) ;▶ Démo
Tester avec Wouter n'est pas différent de tester les applications React régulières. Vous avez souvent besoin d'un moyen de fournir un luminaire pour l'emplacement actuel pour rendre un itinéraire spécifique. Cela peut être facilement fait en échangeant le crochet d'emplacement normal avec memoryLocation . Il s'agit d'une fonction d'initialisateur qui renvoie un crochet que vous pouvez ensuite spécifier dans un Router de niveau supérieur.
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" ) ;
} ) ; Le crochet peut être configuré pour enregistrer l'historique de la navigation. De plus, il est livré avec une fonction navigate pour la navigation externe.
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" ] ) ;
} ) ; Nous avons de bonnes nouvelles pour vous! Si vous êtes un nomade minimaliste de la taille d'un bundle et que vous avez besoin d'un putain de routage simple dans votre application, vous pouvez simplement utiliser des crochets de localisation nus. Par exemple, useBrowserLocation Hook qui n'est que 650 octets GZiPip et correspond manuellement à l'emplacement actuel:
import { useBrowserLocation } from "wouter/use-browser-location" ;
const UsersRoute = ( ) => {
const [ location ] = useBrowserLocation ( ) ;
if ( location !== "/users" ) return null ;
// render the route
} ;La devise de Wouter est "minimaliste adaptée" .
Les illustrations et les logos de Wouter ont été fabriqués par Katya Simacheva et Katya Vakulenko. Merci à @Jeettiss et à tous les contributeurs incroyables d'avoir aidé au développement.