เอกสารเหล่านี้มีไว้สำหรับ Wouter V3 เท่านั้น โปรดค้นหาเอกสารสำหรับ [email protected] ที่นี่
<Router /> ระดับบนสุดเป็น ตัวเลือกอย่างสมบูรณ์Route ที่คุ้นเคย Link Switch และ Redirect ส่วนประกอบuseLocation , useRoute และ useRouter ... ฉันรัก Wouter มันมีตะขอเล็ก ๆ ที่โอบกอดอย่างเต็มที่และมี API ที่ใช้งานง่ายและเปลือยเปล่า ฉันสามารถทำทุกอย่างให้สำเร็จด้วย React-Router ด้วย Wouter และมันก็รู้สึก เรียบง่ายขึ้นในขณะที่ไม่สะดวก
Matt Miller ระบบนิเวศปฏิกิริยาที่ครบถ้วนสำหรับปี 2020
Wouter ให้ API ง่าย ๆ ที่นักพัฒนาและผู้เขียนห้องสมุดหลายคนชื่นชม โครงการที่โดดเด่นบางโครงการที่ใช้ Wouter: Ultra , React-Three-Three , Sunmao UI , Million และอีกมากมาย
เริ่มต้น
wouter api
hooks api
useRoute : การจับคู่เส้นทางและพารามิเตอร์useLocation : การทำงานกับประวัติศาสตร์useParams : การแยกพารามิเตอร์ที่ตรงกันuseSearch : Strings QueryuseRouter : การเข้าถึงวัตถุเราเตอร์ส่วนประกอบ 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
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+ หากคุณต้องการสนับสนุนเบราว์เซอร์รุ่นเก่าตรวจสอบให้แน่ใจว่าคุณ transpile node_modules นอกจากนี้เวอร์ชัน typescript ขั้นต่ำที่รองรับคือ 4.1 เพื่อรองรับการอนุมานพารามิเตอร์เส้นทาง
Wouter มาพร้อมกับ APIs สามชนิด: ตะขอตำแหน่งสแตนด์อโลน ระดับต่ำ, ตะขอสำหรับ การกำหนดเส้นทางและการจับคู่รูปแบบ และ API ที่ใช้ส่วนประกอบ แบบดั้งเดิมมากขึ้นคล้ายกับ React Router's One
คุณมีอิสระที่จะเลือกอะไรก็ได้สำหรับคุณ: ใช้ตะขอตำแหน่งเมื่อคุณต้องการให้แอปของคุณเล็กที่สุดเท่าที่จะเป็นไปได้และไม่ต้องการการจับคู่รูปแบบ ใช้ตะขอการกำหนดเส้นทางเมื่อคุณต้องการสร้างส่วนประกอบการกำหนดเส้นทางที่กำหนดเอง หรือหากคุณกำลังสร้างแอพแบบดั้งเดิมที่มีหน้าและการนำทาง - ส่วนประกอบอาจมีประโยชน์
ตรวจสอบสูตรคำถามที่พบบ่อยและรหัสสำหรับสิ่งต่าง ๆ เช่นลิงก์ที่ใช้งานอยู่เส้นทางเริ่มต้นการเรนเดอร์ฝั่งเซิร์ฟเวอร์ ฯลฯ
ตะขอตำแหน่ง
สิ่งเหล่านี้สามารถใช้แยกต่างหากจากโมดูลหลักและมีอินเทอร์เฟซคล้ายกับ useState ตะขอเหล่านี้ไม่รองรับการทำรังเส้นทางฐานการจับคู่เส้นทาง
import { useBrowserLocation } from "wouter/use-browser-location" -อนุญาตให้จัดการตำแหน่งปัจจุบันในแถบที่อยู่ของเบราว์เซอร์ซึ่งเป็นเสื้อคลุมเล็ก ๆ รอบ API ประวัติศาสตร์import { useHashLocation } from "wouter/use-hash-location" -ในทำนองเดียวกันได้รับตำแหน่งจากส่วนแฮชของที่อยู่เช่นสตริงหลังจาก #import { memoryLocation } from "wouter/memory-location" -เบ็ดที่ตั้งในหน่วยความจำพร้อมการสนับสนุนประวัติการนำทางภายนอกและโหมดไม่เปลี่ยนรูปสำหรับการทดสอบ หมายเหตุ ชื่อโมดูลเนื่องจากเป็นตะขอลำดับสูง ดูว่าตำแหน่งหน่วยความจำสามารถใช้ในการทดสอบได้อย่างไรขอเส้นทาง
นำเข้าจากโมดูล wouter
useRoute - แสดงว่าหน้าปัจจุบันตรงกับรูปแบบที่ให้ไว้หรือไม่useLocation - อนุญาตให้จัดการตำแหน่งของเราเตอร์ปัจจุบันโดยสมัครสมาชิกค่าเริ่มต้นไปยังตำแหน่งเบราว์เซอร์ หมายเหตุ: นี่ไม่เหมือนกับ useBrowserLocation อ่านด้านล่างuseParams - ส่งคืนวัตถุที่มีพารามิเตอร์ที่ตรงกับเส้นทางที่ใกล้ที่สุดuseSearch - ส่งคืนสตริงการค้นหา - ทุกอย่างที่เกิดขึ้นหลังจาก ? -useRouter - ส่งคืนวัตถุเราเตอร์ทั่วโลกที่ถือการกำหนดค่า ใช้เฉพาะในกรณีที่คุณต้องการปรับแต่งเส้นทางส่วนประกอบ
นำเข้าจากโมดูล wouter
<Route /> - แสดงส่วนประกอบตามเงื่อนไขตามรูปแบบ<Link /> - wraps <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 คู่คือวัตถุที่มีพารามิเตอร์หรือ NULL หากไม่มีการจับคู่ สำหรับกลุ่มไวด์การ์ดชื่อพารามิเตอร์คือ "*" :
// wildcards, matches "/app", "/app-1", "/app/home"
const [ match , params ] = useRoute ( "/app*" ) ;
if ( match ) {
// "/home" for "/app/home"
const page = params [ "*" ] ;
}useLocation : การทำงานกับประวัติศาสตร์ เพื่อให้ได้เส้นทางปัจจุบันและนำทางระหว่างหน้าเว็บให้โทรหา hook useLocation ในทำนองเดียวกันกับ 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 HOOK
วิธีการ setter ของ useLocation ยังสามารถยอมรับวัตถุเสริมที่มีพารามิเตอร์เพื่อควบคุมว่าการอัปเดตการนำทางจะเกิดขึ้นได้อย่างไร
เมื่อใช้ตำแหน่งเบราว์เซอร์ (ค่าเริ่มต้น) Hook useLocation ยอมรับ 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 ใช้ hook useLocation ที่ตอบสนองต่อ 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 มันเป็นเรื่องง่ายและสนุกที่จะสร้าง hooks ที่ตั้งของคุณเอง: 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 } > / >มันเหมือนกันสำหรับเส้นทาง regex กลุ่มจับภาพสามารถเข้าถึงได้โดยดัชนีของพวกเขาหรือหากมีกลุ่มจับภาพชื่อที่สามารถใช้แทนได้
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 : Strings Query ใช้ตะขอนี้เพื่อรับค่าสตริงการค้นหาปัจจุบัน (แบบสอบถาม) มันจะทำให้ส่วนประกอบของคุณแสดงผลอีกครั้งเฉพาะเมื่อสตริงเองและไม่ใช่การอัปเดตตำแหน่งเต็มรูปแบบ สตริงการค้นหาที่ส่งคืน ไม่มี A ? อักขระ.
import { useSearch } from "wouter" ;
// returns "tab=settings&id=1"
// the hook for extracting search parameters is coming soon!
const searchString = useSearch ( ) ; สำหรับ SSR ให้ใช้ Prop ssrSearch ที่ส่งผ่านไปยังเราเตอร์
< 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 Prop ไม่ได้เปลี่ยน regex ที่ส่งผ่านไปยังเส้นทาง Regex แต่ Prop nest จะพิจารณาว่าเส้นทางที่ซ้อนกันจะตรงกับส่วนที่เหลือของเส้นทางหรือเส้นทางเดียวกัน ในการสร้างเส้นทางที่เข้มงวดให้ใช้รูปแบบ regex เช่น /^[/](your pattern)[/]?$/ (สิ่งนี้ตรงกับสแลชปลายที่เป็นตัวเลือกและจุดสิ้นสุดของสตริง) ในการสร้าง regex ที่เป็นรังได้ให้ใช้รูปแบบ regex เช่น /^[/](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 จะถูกเรียกด้วยค่าบูลีนที่ระบุว่าลิงก์นั้นใช้งานได้สำหรับเส้นทางปัจจุบันหรือไม่ คุณสามารถใช้สิ่งนี้กับ LINKS Active Style (เช่นลิงก์ในเมนูการนำทาง)
< 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 ที่ว่างเปล่าสุดท้ายจะถูกใช้เป็นทางเลือก ดูที่ คำถามที่พบบ่อยและรหัสสูตรอาหาร เพื่ออ่านเกี่ยวกับเส้นทางเริ่มต้น
<Redirect to={path} /> เมื่อติดตั้งจะทำการเปลี่ยนเส้นทางไปยัง path ที่ให้ไว้ ใช้ hook useLocation ภายในเพื่อกระตุ้นการนำทางภายในบล็อก useEffect
Redirect ยังสามารถยอมรับอุปกรณ์ประกอบฉากสำหรับการปรับแต่งวิธีการนำทางจะดำเนินการตัวอย่างเช่นการตั้งค่าสถานะประวัติเมื่อนำทาง ตัวเลือกเหล่านี้มีความเฉพาะเจาะจงกับตะขอตำแหน่งที่ใช้ในปัจจุบัน
< Redirect to = "/" />
// arbitrary state object
< Redirect to = "/" state = { { modal : true } } / >
// use `replaceState`
< Redirect to = "/" replace /> หากคุณต้องการตรรกะขั้นสูงเพิ่มเติมสำหรับการนำทางเช่นเพื่อกระตุ้นการเปลี่ยนเส้นทางภายในตัวจัดการเหตุการณ์ให้พิจารณาใช้ hook useLocation แทน:
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 ไม่จำเป็นต้องห่อในองค์ประกอบระดับบนสุด วัตถุเราเตอร์ภายในจะถูกสร้างขึ้นตามความต้องการดังนั้นคุณสามารถเริ่มเขียนแอปของคุณได้โดยไม่ต้องก่อมลพิษด้วยผู้ให้บริการระดับสูง อย่างไรก็ตามมีหลายกรณีเมื่อต้องปรับแต่งพฤติกรรมการกำหนดเส้นทาง
กรณีเหล่านี้รวมถึงการกำหนดเส้นทางที่ใช้แฮช, การสนับสนุน basepath, ฟังก์ชั่นจับคู่แบบกำหนดเอง ฯลฯ
import { useHashLocation } from "wouter/use-hash-location" ;
< Router hook = { useHashLocation } base = "/app" >
{ /* Your app goes here */ }
</ Router > ; เราเตอร์เป็นวัตถุง่าย ๆ ที่มีตัวเลือกการกำหนดค่าการกำหนดเส้นทาง คุณสามารถรับวัตถุนี้ได้เสมอโดยใช้เบ็ด useRouter รายการตัวเลือกที่มีอยู่ในปัจจุบัน:
hook: () => [location: string, setLocation: fn] - เป็นฟังก์ชันเบ็ดปฏิกิริยาที่สมัครรับการเปลี่ยนแปลงตำแหน่ง มันส่งคืนคู่ของสตริง location ปัจจุบันเช่น /app/users และฟังก์ชัน setLocation สำหรับการนำทาง คุณสามารถใช้ตะขอนี้จากส่วนประกอบใด ๆ ของแอปของคุณโดยเรียก useLocation() Hook ดูการปรับแต่งเบ็ดที่ตั้ง
searchHook: () => [search: string, setSearch: fn] - คล้ายกับ hook แต่สำหรับการได้รับสตริงการค้นหาปัจจุบัน
base: string - การตั้งค่าเสริมที่อนุญาตให้ระบุเส้นทางฐานเช่น /app เส้นทางแอปพลิเคชันทั้งหมดจะสัมพันธ์กับเส้นทางนั้น หากต้องการนำทางไปยังเส้นทางที่แน่นอนให้นำหน้าเส้นทางของคุณด้วย ~ ดูคำถามที่พบบ่อย
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" และชื่อพา ธ คือ "/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 Children มีความสำคัญเส้นทางเริ่มต้นควรมาล่าสุดเสมอ
หากคุณต้องการเข้าถึงส่วนที่ตรงกันของเส้นทางคุณสามารถใช้พารามิเตอร์ไวด์การ์ด:
< 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
แทนที่จะเป็นสตริง className ปกติให้ให้ฟังก์ชั่นเพื่อใช้คลาสที่กำหนดเองเมื่อลิงค์นี้ตรงกับเส้นทางปัจจุบัน โปรดทราบว่ามันจะทำการจับคู่ที่แน่นอนเสมอ (เช่น /users จะไม่ทำงานสำหรับ /users/1 )
< Link className = { ( active ) => ( active ? "active" : "" ) } > Nav link </ Link > หากคุณต้องการควบคุมอุปกรณ์ประกอบฉากอื่น ๆ เช่น aria-current หรือ style คุณสามารถเขียน <Link /> wrapper ของคุณเองและตรวจจับว่าเส้นทางนั้นใช้งานได้โดยใช้ hook useRoute หรือไม่
const [ isActive ] = useRoute ( props . href ) ;
return (
< Link { ... props } asChild >
< a style = { isActive ? { color : "red" } : { } } > { props . children } </ a >
</ Link >
) ;▶ Demo Sandbox
หากสแลชต่อท้ายเป็นสิ่งสำคัญสำหรับการกำหนดเส้นทางแอปของคุณคุณสามารถระบุตัวแยกวิเคราะห์ที่กำหนดเองได้ Parser เป็นวิธีที่ใช้สตริงรูปแบบและส่งคืน regexp และอาร์เรย์ของคีย์ที่แยกวิเคราะห์ มันใช้ลายเซ็นของฟังก์ชั่น 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 >
) ;▶ Demo Sandbox
ใช่! เส้นทางใด ๆ ที่มี nest Prop นำเสนอบริบทการทำรัง โปรดทราบว่าตำแหน่งภายในเส้นทางซ้อนจะถูกกำหนดขอบเขต
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
ใช่ฟังก์ชั่น navigate ถูกเปิดเผยจากโมดูล "wouter/use-browser-location" :
import { navigate } from "wouter/use-browser-location" ;
navigate ( "/" , { replace : true } ) ;มันเป็นฟังก์ชั่นเดียวกับที่ใช้ภายใน
ใช่! แม้ว่าโครงการจะไม่ถูกเขียนเป็น typeScript ไฟล์นิยามประเภทจะรวมกับแพ็คเกจ
ลองมาดูกันว่าเส้นทางที่สามารถเคลื่อนไหวได้อย่างไรกับ framer-motion ภาพเคลื่อนไหว Enter Transitions เป็นเรื่องง่าย แต่การเปลี่ยนจากการเปลี่ยนต้องใช้งานได้อีกเล็กน้อย เราจะใช้องค์ประกอบ 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 >
) ;
} ; ตัวอย่างที่ซับซ้อนมากขึ้นเกี่ยวข้องกับการใช้ hook useRoutes (คล้ายกับวิธีที่เราเตอร์ตอบสนอง) แต่ wouter ไม่ได้จัดส่งออกนอกกรอบ โปรดดูปัญหานี้สำหรับวิธีแก้ปัญหา
การส่งออกล่วงหน้ามีให้บริการผ่านแพ็คเกจแยกต่างหากที่ชื่อว่า wouter-preact (หรือภายในเนมสเปซ wouter/preact แต่วิธีนี้ไม่แนะนำให้ใช้เนื่องจากต้องมีการตอบสนองต่อการพึ่งพาเพียร์):
- import { useRoute, Route, Switch } from "wouter";
+ import { useRoute, Route, Switch } from "wouter-preact";คุณอาจต้องตรวจสอบให้แน่ใจว่าคุณมี Preact X เวอร์ชันล่าสุดพร้อมการสนับสนุนตะขอ
▶ Demo Sandbox
ในการแสดงแอปของคุณบนเซิร์ฟเวอร์คุณจะต้องห่อแอปของคุณด้วยเราเตอร์ระดับบนสุดและระบุ ssrPath Prop (โดยปกติมาจากคำขอปัจจุบัน) เป็นทางเลือก 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 นั้นไม่แตกต่างจากการทดสอบแอพตอบสนองปกติ คุณมักจะต้องมีวิธีในการติดตั้งสำหรับตำแหน่งปัจจุบันเพื่อแสดงเส้นทางที่เฉพาะเจาะจง สิ่งนี้สามารถทำได้อย่างง่ายดายโดยการสลับเบ็ดตำแหน่งปกติกับ 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 Hook ซึ่งมีเพียง 650 ไบต์ gzipped และจับคู่ตำแหน่งปัจจุบันด้วยตนเองกับมัน:
import { useBrowserLocation } from "wouter/use-browser-location" ;
const UsersRoute = ( ) => {
const [ location ] = useBrowserLocation ( ) ;
if ( location !== "/users" ) return null ;
// render the route
} ;คำขวัญของ Wouter คือ "Minimalist-friendly"
ภาพประกอบและโลโก้ Wouter ทำโดย Katya Simacheva และ Katya Vakulenko ขอบคุณ @JeetIss และผู้มีส่วนร่วมที่น่าทึ่งสำหรับการช่วยเหลือในการพัฒนา