ReactJS: Hướng dẫn sử dụng Reach Router
Tổng quát
Reach Router là một bộ định tuyến nhỏ, đơn giản cho React vay mượn từ React Router, Ember và Preact Router. Reach Router có dung lượng nhỏ, chỉ hỗ trợ các mẫu route đơn giản theo thiết kế và có các tính năng hỗ trợ truy cập mạnh mẽ.
Tương lai
Reach Router và dự án anh em của nó là React Router được hợp nhất thành React Router v6. Nói cách khác, Reach Router v2 và React Router v6 giống nhau.
Cài đặt
npm install @reach/router
# hoặc
yarn add @reach/router
Reach Router tương thích với React 15+.
Khả năng tiếp cận
Router sẽ quản lý trọng tâm của ứng dụng của bạn về chuyển đổi route. Bạn sẽ không cần làm gì, nó sẽ tự động làm điều đó cho bạn.
Kết xuất (Render)
Router chọn một con để kết xuất dựa trên đường dẫn của nó. Các phần tử con chỉ là các component khác có thể được tự hiển thị bên ngoài Router.
import React from "react"
import { render } from "react-dom"
import { Router, Link } from "@reach/router"
let Home = () => <div>Home</div>
let Dash = () => <div>Dash</div>
render(
<Router>
<Home path="/" />
<Dash path="dashboard" />
</Router>
)
Điều hướng bằng liên kết
Để điều hướng xung quanh ứng dụng, ta sử dụng một Link
.
let Home = () => (
<div>
<h1>Home</h1>
<nav>
<Link to="/">Home</Link> |{" "}
<Link to="dashboard">Dashboard</Link>
</nav>
</div>
)
let Dash = () => <div>Dash</div>
render(
<Router>
<Home path="/" />
<Dash path="dashboard" />
</Router>
)
Phân tích cú pháp dữ liệu từ URL
Nếu bạn cần phân tích cú pháp dữ liệu ra khỏi URL, hãy sử dụng phân đoạn động – chúng bắt đầu bằng một :
. Giá trị được phân tích cú pháp sẽ trở thành giá trị được gửi đến component phù hợp.
// at url "/invoice/23"
render(
<Router>
<Home path="/" />
<Invoice path="invoice/:invoiceId" />
</Router>
)
const Invoice = props => (
<div>
<h1>Invoice {props.invoiceId}</h1>
</div>
)
// or with hooks
const Invoice = () => {
const params = useParams()
return (
<div>
<h1>Invoice {params.invoiceId}</h1>
</div>
)
}
Nó cũng giống như hiển thị trực tiếp component:
<Invoice invoiceId={23} />
Đường dẫn và Xếp hạng không rõ ràng
Mặc dù hai đường dẫn có thể không rõ ràng - như “/:invoiceId” và “/invoices” - Router xếp hạng các đường dẫn và hiển thị đường dẫn có ý nghĩa nhất.
render(
<Router>
<Home path="/" />
<Invoice path=":invoiceId" />
<InvoiceList path="invoices" />
</Router>
)
URL “/invoices” sẽ kết xuất <InvoiceList/>
và “/123” sẽ kết xuất <Invoice invoiceId={123}/>
. Điều này cũng tương tự với component Home
. Mặc dù nó được xác định trước và mọi đường dẫn sẽ khớp với “/”, Home
sẽ không hiển thị trừ khi đường dẫn chính xác là “/”. Vì vậy, đừng lo lắng về thứ tự của các đường dẫn của bạn.
Các đường dẫn component lồng nhau
Bạn có thể lồng các component bên trong Router và các đường dẫn cũng sẽ lồng vào nhau. Component con đã so khớp sẽ xuất hiện dưới dạng prop children
, giống như khi bạn hiển thị trực tiếp. (Bên trong Router
chỉ kết xuất một Router
khác,).
const Dash = ({ children }) => (
<div>
<h1>Dashboard</h1>
<hr />
{children}
</div>
)
render(
<Router>
<Home path="/" />
<Dash path="dashboard">
<Invoices path="invoices" />
<Team path="team" />
</Dash>
</Router>
)
Nếu URL là “/dashboard/invoices” thì Router sẽ hiển thị <Dash><Invoices/></Dash>
. Nếu nó chỉ là “/dashboard”, children
sẽ là null
và chúng ta sẽ chỉ thấy <Dash/>
.
Hầu hết các ứng dụng có thể có một số loại chrome/điều hướng tổng thể hoạt động tốt:
const Main = ({ children }) => (
<div>
<h1>Welcome to the App!</h1>
<ul>
<li>
<Link to="dashboard">Dashboard</Link>
</li>
<li>
<Link to="invoices">Invoices</Link>
</li>
</ul>
<hr />
{children}
</div>
)
render(
<Router>
<Main path="/">
<Invoices path="invoices" />
<Dash path="dashboard" />
</Main>
</Router>
)
Liên kết tương đối
Bạn có thể liên kết đến các đường dẫn tương đối. Thuyết tương đối đến từ đường dẫn của component hiển thị Link. Hai liên kết sau sẽ liên kết đến “/dashboard/invoices” và “/dashboard/team” vì chúng được hiển thị bên trong <Dash/>
. Điều này thực sự tốt khi bạn thay đổi URL của cha hoặc di chuyển các component xung quanh.
render(
<Router>
<Home path="/" />
<Dash path="dashboard">
<Invoices path="invoices" />
<Team path="team" />
</Dash>
</Router>
)
const Dash = ({ children }) => (
<div>
<h1>Dashboard</h1>
<nav>
<Link to="invoices">Invoices</Link>{" "}
<Link to="team">Team</Link>
</nav>
<hr />
{children}
</div>
)
Điều này cũng làm cho việc hiển thị bất kỳ phần nào trong ứng dụng của bạn dưới dạng ứng dụng riêng với bộ định tuyến của chính nó cũng trở nên đơn giản. Nếu tất cả các liên kết của bạn là tương đối, nó có thể được nhúng vào bên trong bất kỳ bộ định tuyến nào khác.
Đường dẫn "Chỉ mục"
Các component lồng nhau có thể sử dụng đường dẫn /
để biểu thị chúng sẽ hiển thị tại đường dẫn của component cha, như tệp index.html bên trong một thư mục trên máy chủ tĩnh. Nếu ứng dụng này ở “/dashboard”, chúng ta sẽ thấy cây component này: <Dash><DashboardGraphs/></Dash>
render(
<Router>
<Home path="/" />
<Dash path="dashboard">
<DashboardGraphs path="/" />
<InvoiceList path="invoices" />
</Dash>
</Router>
)
Không tìm thấy component "Mặc định"
Đặt một prop mặc định trên một component và Router sẽ hiển thị nó khi không có gì khác phù hợp.
const NotFound = () => (
<div>Sorry, nothing here.</div>
)
render(
<Router>
<Home path="/" />
<Dash path="dashboard">
<DashboardGraphs path="/" />
<InvoiceList path="invoices" />
</Dash>
<NotFound default />
</Router>
)
Nhiều bộ định tuyến
Nếu bạn muốn khớp cùng một đường dẫn ở hai nơi trong ứng dụng của mình, bạn chỉ cần kết xuất hai Router. Một lần nữa, một Router chọn một con duy nhất để hiển thị dựa trên URL, và sau đó bỏ qua phần còn lại.
Chỉ cần đảm bảo đánh dấu (các) bộ định tuyến không phải là chính primary={false}
để nó không quản lý sự tập trung vào các component đó.
render(
<div>
<Sidebar>
<Router primary={false}>
<HomeNav path="/" />
<DashboardNav path="dashboard" />
</Router>
</Sidebar>
<MainScreen>
<Router>
<Home path="/">
<About path="about" />
<Support path="support" />
</Home>
<Dash path="dashboard">
<Invoices path="invoices" />
<Team path="team" />
</Dash>
</Router>
</MainScreen>
</div>
)
Bộ định tuyến nhúng
Bạn có thể hiển thị một bộ định tuyến ở bất kỳ đâu bạn muốn trong ứng dụng của mình, thậm chí sâu bên trong Bộ định tuyến khác, chỉ cần đảm bảo sử dụng một splat (*
) trên component cha để các đường dẫn lồng nhau khớp với nó.
render(
<Router>
<Home path="/" />
<Dash path="dashboard/*" />
</Router>
)
const Dash = () => (
<div>
<p>A nested router</p>
<Router>
<DashboardGraphs path="/" />
<InvoiceList path="invoices" />
</Router>
</div>
)
Điều này cho phép bạn định cấu hình tất cả các router của mình ở đầu ứng dụng hoặc chỉ định cấu hình ở những nơi bạn cần, điều này thực sự hữu ích cho việc phân tách mã và các ứng dụng rất lớn. Bạn thậm chí có thể hiển thị Dash
như một ứng dụng độc lập.
Điều hướng theo chương trình
Nếu bạn cần điều hướng theo chương trình (như sau khi gửi biểu mẫu), bạn hãy dùng useNavigate
.
import { useNavigate } from "@reach/router"
const Invoices = () => {
const navigate = useNavigate()
return (
<div>
<NewInvoiceForm
onSubmit={async event => {
const newInvoice = await createInvoice(
event.target
)
navigate(`/invoices/${newInvoice.id}`)
}}
/>
</div>
)
}
Hoặc tốt hơn, sử dụng props.navigate
được chuyển cho các component route của bạn và sau đó bạn có thể điều hướng đến các đường dẫn tương đối:
const Invoices = ({ navigate }) => (
<div>
<NewInvoiceForm
onSubmit={async event => {
const newInvoice = await createInvoice(
event.target
)
// can navigate to relative paths
navigate(newInvoice.id)
}}
/>
</div>
)
;<Router>
<Invoices path="invoices" />
<Invoice path="invoices/:id" />
</Router>
Điều hướng trả về một promise để bạn có thể chờ đợi nó. Nó sẽ giải quyết sau khi React hoàn tất kết xuất màn hình tiếp theo, ngay cả với React Suspense.
import { navigate } from "@reach/router"
class Invoices extends React.Component {
state = {
creatingNewInvoice: false
}
render() {
return (
<div>
<LoadingBar
animate={this.state.creatingNewInvoice}
/>
<NewInvoiceForm
onSubmit={async event => {
this.setState({
creatingNewInvoice: true
})
const newInvoice = await createInvoice(
event.target
)
await navigate(
`/invoice/${newInvoice.id}`
)
this.setState({
creatingNewInvoice: false
})
}}
/>
<InvoiceList />
</div>
)
}
}