️ Эти документы предназначены только для Wouter v3. Пожалуйста, найдите документацию для [email protected] здесь
<Router /> , он полностью необязательно .Route , Link , Switch и Redirect компонентов.useLocation , useRoute и useRouter . ... Я люблю Вутер. Он крошечный, полностью охватывает крючки и имеет интуитивно понятный и Barebones API. Я могу выполнить все, что мог с React-Router с Wouter, и это просто кажется более минималистским, хотя и не неудобно.
Мэтт Миллер , исчерпывающая экосистема реагирования на 2020 год
Wouter предоставляет простой API, который ценят многие разработчики и библиотечные авторы. Некоторые известные проекты, в которых используются Wouter: Ultra , React-три волокна , пользовательский интерфейс Sunmao , миллион и многое другое.
Начиная
Wouter API
Крюки API
useRoute : Сопоставление маршрутов и параметрыuseLocation : работа с историейuseParams : извлечение соответствующих параметровuseSearch : Строки запросаuseRouter : доступ к объекту маршрутизатораКомпонент API
<Route path={pattern} /><Link href={path} /><Switch /><Redirect to={path} /><Router hook={hook} parser={fn} base={basepath} />Рецепты часто задаваемых данных и кода
Благодарности
Во -первых, добавьте Wouter в свой проект.
npm i wouter Или, если вы используете Preact, используйте следующую команду npm i wouter-preact .
Проверьте это простое демонстрационное приложение ниже. Он не охватывает крючки и другие функции, такие как вложенная маршрутизация, но это хорошая отправная точка для тех, кто мигрирует с React Router.
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 >
</ >
) ; Эта библиотека предназначена для совместимости ES2020+ . Если вам нужно поддерживать более старые браузеры, убедитесь, что вы транспилируют node_modules . Кроме того, минимальная поддерживаемая версия TypeScript составляет 4.1 для поддержки вывода параметров маршрута.
Wouter поставляется с тремя видами API: автономные крючки местоположения низкого уровня, крючки для маршрутизации и сопоставление рисунков и более традиционный API на основе компонентов, похожий на Rouct Router One.
Вы можете выбрать все, что работает для вас: используйте крючки местоположения, когда вы хотите сохранить свое приложение как можно меньше, и вам не нужно сопоставлять шаблоны; Используйте крючки маршрутизации, когда вы хотите создать пользовательские компоненты маршрутизации; Или, если вы создаете традиционное приложение с страницами и навигацией - компоненты могут пригодиться.
Проверьте также FAQ и рецепты кода для более продвинутых вещей, таких как активные ссылки, маршруты по умолчанию, рендеринг на стороне сервера и т. Д.
Местоположение крючки
Они могут использоваться отдельно от основного модуля и иметь интерфейс, аналогичный useState . Эти крючки не поддерживают гнездование, базовый путь, сопоставление маршрутов.
import { useBrowserLocation } from "wouter/use-browser-location" -позволяет манипулировать текущим местоположением в адресной панели браузера, крошечной обертке вокруг API истории.import { useHashLocation } from "wouter/use-hash-location" -аналогично, получает место от хэш-части адреса, то есть строка после # .import { memoryLocation } from "wouter/memory-location" -крюк в памяти с поддержкой истории, внешняя навигация и неподвижный режим для тестирования. Обратите внимание на название модуля, потому что это крючок высокого порядка. Посмотрите, как расположение памяти можно использовать при тестировании.Маршрутизация крючков
Импорт из wouter Module.
useRoute - показывает, соответствует ли текущая страница предоставленную шаблон.useLocation - позволяет манипулировать местоположением текущего маршрутизатора, по умолчанию подписывается на местоположение браузера. Примечание. Это не то же самое, что useBrowserLocation , прочитайте ниже.useParams - возвращает объект с параметрами, сопоставленными с ближайшего маршрута.useSearch - возвращает строку поиска - все, что идет после ? ПолемuseRouter - возвращает глобальный объект маршрутизатора, который удерживает конфигурацию. Используйте его только в том случае, если вы хотите настроить маршрутизацию.Компоненты
Импорт из wouter Module.
<Route /> - условное предъявляет компонент на основе шаблона.<Link /> - Обертывание <a> , позволяет выполнить навигацию.<Switch /> - Эксклюзивная маршрутизация, только отдает первое подходящее маршрут.<Redirect /> - при переводе, выполняет немедленную навигацию.<Router /> -необязательный компонент верхнего уровня для расширенной конфигурации маршрутизации. useRoute : Сопоставление маршрутов и параметры Проверяет, соответствует ли текущее местоположение предоставленную шаблон, и возвращает объект с параметрами. Это основано на прекрасной библиотеке regexparam , поэтому весь его синтаксис шаблона полностью поддерживается.
Вы можете использовать useRoute для выполнения ручной маршрутизации или реализации пользовательской логики, такой как переходы маршрутов и т. Д.
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 ;
}
} ;Быстрый чит, какие типы сегментов поддерживаются:
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]+)[/]?$ / ) ; Второй элемент в паре params - это объект с параметрами или нулевым, если не было совпадения. Для сегментов подстановочного знака имя параметра "*" :
// wildcards, matches "/app", "/app-1", "/app/home"
const [ match , params ] = useRoute ( "/app*" ) ;
if ( match ) {
// "/home" for "/app/home"
const page = params [ "*" ] ;
}useLocation : работа с историей Чтобы получить текущий путь и перейти между страницами, позвоните в useLocation Hook. Подобно useState , он возвращает значение и сеттер: компонент будет повторно рендеринг при изменении местоположения, и, вызывая navigate вы можете обновить это значение и выполнить навигацию.
По умолчанию он использует useBrowserLocation под капотом, хотя вы можете настроить это в компоненте Router верхнего уровня (например, если вы решите в какой-то момент переключиться на маршрутизацию на основе хэша). useLocation также вернет путь крезок при использовании в пределах вложенных маршрутов или с настройкой базового пути.
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 >
) ;
} ; Все компоненты внутренне называют крючком useLocation .
Метод сеттера useLocation также может принять дополнительный объект с параметрами для управления тем, как будет обновление навигации.
Когда используется местоположение браузера (по умолчанию), useLocation Hook replace Flag, чтобы сообщить Hook для изменения текущей записи истории вместо добавления новой. Это то же самое, что называть replaceState .
const [ location , navigate ] = useLocation ( ) ;
navigate ( "/jobs" ) ; // `pushState` is used
navigate ( "/home" , { replace : true } ) ; // `replaceState` is used Кроме того, вы можете предоставить state для обновления history.state во время навигации:
navigate ( "/home" , { state : { modal : "promo" } } ) ;
history . state ; // { modal: "promo" } По умолчанию Wouter использует useLocation Hook, который реагирует на навигацию pushState и replaceState через useBrowserLocation .
Чтобы настроить это, оберните свое приложение в компонент Router :
import { Router , Route } from "wouter" ;
import { useHashLocation } from "wouter/use-hash-location" ;
const App = ( ) => (
< Router hook = { useHashLocation } >
< Route path = "/about" component = { About } />
...
</ Router >
) ; Поскольку эти крючки имеют возвратные значения, аналогичные useState , легко и весело создавать свои собственные крючки с местоположением: useCrossTabLocation , useLocalStorage , useMicroFrontendLocation и любую логику маршрутизации, которую вы хотите поддерживать в приложении. Попробуйте!
useParams : извлечение соответствующих параметров Этот крюк позволяет вам получить доступ к параметрам, обнаруженным посредством соответствующих динамических сегментов. Внутренне мы просто обертываем ваши компоненты в поставщика контекста, позволяя вам получить доступ к этим данным в любом месте в компоненте Route .
Это позволяет вам избежать «бурения опоры» при работе с глубоко вложенными компонентами в пределах маршрута. Примечание. useParams извлекут только параметры из ближайшего родительского маршрута.
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 } > / >Это то же самое для пути корпорации. Заемные группы могут быть доступны по их индексу, или если есть именованная группа захвата, которая может быть использована вместо этого.
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 : Строки запроса Используйте этот крюк, чтобы получить текущее значение строки поиска (запрос). Это приведет к тому, что ваш компонент будет повторно рендеринг только тогда, когда сама строка, а не обновления полного местоположения. Возвращенная строка поиска не содержит ? характер.
import { useSearch } from "wouter" ;
// returns "tab=settings&id=1"
// the hook for extracting search parameters is coming soon!
const searchString = useSearch ( ) ; Для SSR используйте ssrSearch Prop, переданный на маршрутизатор.
< Router ssrSearch = { request . search } > { /* SSR! */ } </ Router >Обратитесь к рендеринге на стороне сервера для получения дополнительной информации о рендеринге и увлажнении.
useRouter : доступ к объекту маршрутизатора Если вы создаете расширенную интеграцию, например, на пользовательский крючок местоположение, вы можете получить доступ к объекту глобального маршрутизатора. Маршрутизатор - это простой объект, который содержит параметры маршрутизации, которые вы настраиваете в компоненте 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 представляет часть приложения, которая оказана условно на основе path шаблона. Паттерн имеет тот же синтаксис, что и аргумент, который вы передаете useRoute .
Библиотека предоставляет несколько способов объявить тело маршрута:
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 } /> Считается, что маршрут без пути всегда совпадает, и он такой же, как <Route path="*" /> . При разработке вашего приложения используйте этот трюк, чтобы заглянуть на контент маршрута без навигации.
- <Route path="/some/page">
+ <Route>
{/* Strip out the `path` to make this visible */}
</Route> Гнездование является основной особенностью Wouter и может быть включено на маршруте через nest Prop. Когда эта опора присутствует, маршрут соответствует всему, что начинается с заданного шаблона, и создает вложенный контекст маршрутизации. Все дочерние маршруты получат местоположение по сравнению с этой моделью.
Давайте посмотрим на этот пример:
< Route path = "/app" nest >
< Route path = "/users/:id" nest >
< Route path = "/orders" />
</ Route >
</ Route > Этот первый маршрут будет активен для всех путей, которые начинаются с /app , это эквивалентно наличию базового пути в вашем приложении.
Второй использует динамический шаблон, чтобы соответствовать таким путям, как /app/user/1 , /app/user/1/anything и так далее.
Наконец, внутренний маршрут будет работать только для путей, которые выглядят как /app/users/1/orders . Матч строго, поскольку этот маршрут не имеет опоры nest , и он работает как обычно.
Если вы позвоните useLocation() в последнем маршруте, он вернет /orders , а не /app/users/1/orders . Это создает хорошую изоляцию, и это облегчает вносить изменения в родительский маршрут, не беспокоясь о том, что остальная часть приложения перестанет работать. Если вам нужно перейти на страницу верхнего уровня, вы можете использовать префикс ~ для обозначения абсолютного пути:
< Route path = "/payments" nest >
< Route path = "/all" >
< Link to = "~/home" > Back to Home </ Link >
</ Route >
</ Route > ПРИМЕЧАНИЕ. Предоставление nest не изменяет режиму, проходящую в пути корпорации. Вместо этого опора nest будет только определять, будут ли вложенные маршруты совпадать с остальной частью пути или по тому же пути. Чтобы сделать строгий режим пути, используйте рисунок резервуара, такой как /^[/](your pattern)[/]?$/ Чтобы создать гнездовое регуляцию, используйте рисунок резервуара, например /^[/](your pattern)(?=$|[/])/
<Link href={path} /> Компонент ссылки отображает элемент <a /> , который при нажатии выполняет навигацию.
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 } } / > Ссылка всегда будет обернуть своих детей в тег <a /> , если не предоставлена asChild Prop. Используйте это, когда вам нужно иметь пользовательский компонент, который отдает <a /> под капюшоном.
// use this instead
< Link to = "/" asChild >
< UIKitLink />
</ Link >
// Remember, `UIKitLink` must implement an `onClick` handler
// in order for navigation to work! Когда вы передаете функцию в качестве опоры className , она будет вызвана с логическим значением, указывающим, активна ли ссылка для текущего маршрута. Вы можете использовать это для стиля активных ссылок (например, для ссылок в меню навигации)
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav </ Link >Узнайте больше о активных ссылках здесь.
<Switch /> Есть случаи, когда вы хотите иметь эксклюзивную маршрутизацию: чтобы убедиться, что в то время отображается только один маршрут, даже если у маршрутов есть шаблоны, которые перекрываются. Вот что делает Switch : он только делает первый соответствующий маршрут .
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 > ; Когда маршрут в коммутаторе не соответствует, последний пустой Route будет использоваться в качестве запасного. См. Раздел FAQ и Code рецептов , чтобы прочитать о маршрутах по умолчанию.
<Redirect to={path} /> При установке выполняет перенаправление на предоставленный path . Использует useLocation Hook внутри, чтобы запустить навигацию внутри блока useEffect .
Redirect также может принять реквизиты для настройки того, как будет выполнена навигация, например, для установки состояния истории при навигации. Эти варианты специфичны для в настоящее время используемого крючка местоположения.
< Redirect to = "/" />
// arbitrary state object
< Redirect to = "/" state = { { modal : true } } / >
// use `replaceState`
< Redirect to = "/" replace /> Если вам нужна более продвинутая логика для навигации, например, чтобы запустить перенаправление внутри обработчика событий, вместо этого рассмотрите возможность использования useLocation Hook:
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} />В отличие от маршрутизатора React , маршруты в Wouter не должны быть завернуты в компонент верхнего уровня . Внутренний объект маршрутизатора будет построен по требованию, поэтому вы можете начать писать свое приложение, не загрязняя его каскадом поставщиков высшего уровня. Есть случаи, однако, когда необходимо настроить поведение маршрутизации.
Эти случаи включают маршрутизацию на основе хэша, поддержку базепа, пользовательскую функцию совпадения и т. Д.
import { useHashLocation } from "wouter/use-hash-location" ;
< Router hook = { useHashLocation } base = "/app" >
{ /* Your app goes here */ }
</ Router > ; Маршрутизатор - это простой объект, который содержит параметры конфигурации маршрутизации. Вы всегда можете получить этот объект, используя крюк useRouter . Список доступных в настоящее время параметров:
hook: () => [location: string, setLocation: fn] - это функция React Hook, которая подписывается на изменения местоположения. Он возвращает пару текущей строки location , например /app/users и функцию setLocation для навигации. Вы можете использовать этот крюк из любого компонента вашего приложения, вызывая useLocation() крючок. Смотрите настройку крючка местоположения.
searchHook: () => [search: string, setSearch: fn] - аналогично hook , но для получения текущей строки поиска.
base: string - необязательная настройка, которая позволяет указать базовый путь, такой как /app . Все маршруты приложений будут относительно этого пути. Чтобы перейти к абсолютному пути, префиксу свой путь с ~ . Смотрите FAQ.
parser: (path: string, loose?: boolean) => { pattern, keys } - функция анализа шаблона. Создает REGEXP для сопоставления текущего местоположения с пользовательскими шаблонами, такими как /app/users/:id . Имеет тот же интерфейс, что и функция parse от regexparam . Смотрите этот пример, который демонстрирует пользовательскую функцию анализатора.
ssrPath: string и ssrSearch: string Используйте их при рендеринге вашего приложения на сервере.
hrefs: (href: boolean) => string - функция для преобразования атрибута href элемента <a /> , отображаемого по Link . Он используется для поддержки маршрутизации на основе хэша. По умолчанию атрибут href такой же, как у href или to опоры Link . Крюк местоположения также может определить свойство hook.hrefs , в данном случае href будет выведен.
Ты можешь! Заверните ваше приложение <Router base="/app" /> , и это должно сделать трюк:
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 >
) ; Вызов useLocation() в маршруте в приложении с базовым путем вернет путь, приспособленный к основанию. Это означает, что когда базовая является "/app" , а PathName - "/app/users" возвращаемая строка - это "/users" . Соответственно, вызов navigate автоматически добавит базу к аргументу пути для вас.
Когда у вас есть несколько вложенных маршрутизаторов, базовые пути наследуют и сложены.
< Router base = "/app" >
< Router base = "/cms" >
< Route path = "/users" > Path is /app/cms/users! </ Route >
</ Router >
</ Router > Одним из распространенных шаблонов в маршрутизации приложений является маршрут по умолчанию, который будет показан в виде резерва, в случае никакого другого сравнения маршрута (например, если вам нужно отобразить 404 сообщение). В Wouter это можно легко сделать в виде комбинации компонента <Switch /> и маршрута по умолчанию:
import { Switch , Route } from "wouter" ;
< Switch >
< Route path = "/about" > ... </ Route >
< Route > 404, Not Found! </ Route >
</ Switch > ;Примечание. Порядок переключения детей имеет значение, маршрут по умолчанию всегда должен быть последним.
Если вы хотите иметь доступ к соответствующему сегменту пути, вы можете использовать параметры подстановочного знака:
< 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 >▶ Демонстраовая песочница
Вместо обычной строки className , предоставьте функцию использования пользовательского класса, когда эта ссылка соответствует текущему маршруту. Обратите внимание, что он всегда будет выполнять точное совпадение (т.е. /users не будут активны для /users/1 ).
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav link </ Link > Если вам нужно управлять другими реквизитами, такими как aria-current или style , вы можете написать свою собственную обертку <Link /> и определить, является ли путь активным, используя крючок useRoute .
const [ isActive ] = useRoute ( props . href ) ;
return (
< Link { ... props } asChild >
< a style = { isActive ? { color : "red" } : { } } > { props . children } </ a >
</ Link >
) ;▶ Демонстраовая песочница
Если для маршрутизации вашего приложения важна запекающая черта, вы можете указать пользовательский анализатор. Парсер - это метод, который принимает строку шаблона и возвращает резервуар и массив проанализированного ключа. Он использует подпись функции parse от regexparam .
Давайте напишем пользовательский анализатор на основе популярного пакета path-to-regexp , который поддерживает опцию строгих маршрутов.
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 >
) ;▶ Демонстраовая песочница
Да! Любой маршрут с представленной пропорцией nest создает контекст гнездования. Имейте в виду, что расположение внутри вложенного маршрута будет охвачено.
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 >
) ;▶ Демонстраовая песочница
Да, функция navigate выявляется из модуля "wouter/use-browser-location" :
import { navigate } from "wouter/use-browser-location" ;
navigate ( "/" , { replace : true } ) ;Это та же функция, которая используется внутри.
Да! Хотя проект не записан в TypeScript, файлы определения типа связаны с пакетом.
Давайте посмотрим на то, как в framer-motion можно оживить маршруты. Анимировать переходы ввода легко, но переходы выхода требуют немного большей работы. Мы будем использовать компонент AnimatePresence , который будет держать страницу в DOM, пока анимация выхода не будет завершена.
К сожалению, AnimatePresence только анимирует своих прямых детей , так что это не сработает:
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 >
) ; Обходной путь состоит в том, чтобы соответствовать этому маршруту вручную с useRoute :
export const MyComponent = ( { isVisible } ) => {
const [ isMatch ] = useRoute ( "/" ) ;
return (
< AnimatePresence >
{ isMatch && (
< motion . div
initial = { { opacity : 0 } }
animate = { { opacity : 1 } }
exit = { { opacity : 0 } }
/>
) }
</ AnimatePresence >
) ;
} ; Более сложные примеры включают в себя использование useRoutes Hook (аналогично тому, как это делает маршрутизатор React), но Wouter не отправляет его из коробки. Пожалуйста, обратитесь к этому вопросу об обходном пути.
Exports Preact доступен через отдельный пакет с именем wouter-preact (или в пространстве имен wouter/preact , однако этот метод не рекомендуется, поскольку он требует реагирования как зависимость от сверстников):
- import { useRoute, Route, Switch } from "wouter";
+ import { useRoute, Route, Switch } from "wouter-preact";Возможно, вам понадобится убедиться, что у вас есть последняя версия Preact X с поддержкой крючков.
▶ Демонстраовая песочница
Чтобы отобрать ваше приложение на сервере, вам нужно обернуть приложение маршрутизатором верхнего уровня и указать Prop ssrPath (обычно, полученный из текущего запроса). Необязательно, Router принимает параметр ssrSearch если необходимо иметь доступ к строке поиска на сервере.
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
} ; Совет: Wouter может предварительно заполнить ssrSearch , если ssrPath содержит ? характер. Итак, они эквивалентны:
< Router ssrPath = "/goods?sort=asc" /> ;
// is the same as
< Router ssrPath = "/goods" ssrSearch = "sort=asc" /> ; На клиенте статическая разметка должна быть увлажена, чтобы ваше приложение стало интерактивным. Обратите внимание, что чтобы избежать предупреждений о гидратации, JSX, отображаемый на клиенте, должен соответствовать тому, что используется сервером, поэтому должен присутствовать компонент Router .
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 >
) ;▶ Демонстрация
Тестирование с Wouter ничем не отличается от тестирования регулярных приложений React. Вам часто нужен способ обеспечить приспособление для текущего местоположения, чтобы отобразить конкретный маршрут. Это можно легко сделать, заменив крюк с обычным местоположением с помощью memoryLocation . Это функция инициализатора, которая возвращает крючок, который вы можете указать в Router верхнего уровня.
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" ) ;
} ) ; Крюк может быть настроен для записи истории навигации. Кроме того, он поставляется с функцией navigate для внешней навигации.
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" ] ) ;
} ) ; У нас есть отличные новости для вас! Если вы минималистский кочевник размером с пакет, и вам нужна чертовски простой маршрутизацию в вашем приложении, вы можете просто использовать крючки с локацией. Например, крюк useBrowserLocation , который составляет всего 650 байт GZEPIPD и вручную соответствует текущему местоположению с ним:
import { useBrowserLocation } from "wouter/use-browser-location" ;
const UsersRoute = ( ) => {
const [ location ] = useBrowserLocation ( ) ;
if ( location !== "/users" ) return null ;
// render the route
} ;Девиз Вутера «минималистский» .
Иллюстрации и логотипы Вутера были сделаны Катьей Симачевой и Катья Вакуленко. Спасибо @Jetisis и всем удивительным участникам за помощь в разработке.