github地址:https://github.com/remix-run/react-router/blob/main/docs/getting-started/tutorial.md
demo地址:https://stackblitz.com/edit/github-agqlf5
一、安装
npm install react-router-dom@6
二、使用 BrowserRouter, Routes, Route
这里注意与 v5 的区别
Routes
组件替换v5
的Switch
组件;Route
的component
和render
属性废弃,统一改用element
属性,注意它接受一个jsx
元素,而非组件。
import { render } from "react-dom";
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";
const rootElement = document.getElementById("root");
render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />} />
</Routes>
</BrowserRouter>,
rootElement
);
getInvoices (示例数据文件 无实际作用)
let invoices = [
{
name: "Santa Monica",
number: 1995,
amount: "$10,800",
due: "12/05/1995",
},
{
name: "Stankonia",
number: 2000,
amount: "$8,000",
due: "10/31/2000",
},
{
name: "Ocean Avenue",
number: 2003,
amount: "$9,500",
due: "07/22/2003",
},
{
name: "Tubthumper",
number: 1997,
amount: "$14,000",
due: "09/01/1997",
},
{
name: "Wide Open Spaces",
number: 1998,
amount: "$4,600",
due: "01/27/1998",
},
];
export function getInvoices() {
return invoices;
}
三、跳转方式 Link、NavLink的使用
3.1 Link
import { Link } from "react-router-dom";
export default function App() {
return (
<div>
<h1>Bookkeeper</h1>
<nav
style={{
borderBottom: "solid 1px",
paddingBottom: "1rem",
}}
>
<Link to="/invoices">Invoices</Link> |{" "}
<Link to="/expenses">Expenses</Link>
</nav>
</div>
);
}
3.2 NavLink的使用
import { NavLink, Outlet } from "react-router-dom";
import { getInvoices } from "../data";
export default function Invoices() {
let invoices = getInvoices();
return (
<div style={{ display: "flex" }}>
<nav
style={{
borderRight: "solid 1px",
padding: "1rem",
}}
>
{invoices.map((invoice) => (
<NavLink
style={({ isActive }) => {
return {
display: "block",
margin: "1rem 0",
color: isActive ? "red" : "",
};
}}
to={`/invoices/${invoice.number}`}
key={invoice.number}
>
{invoice.name}
</NavLink>
))}
</nav>
<Outlet />
</div>
);
}
- 我们换Link了NavLink。
- 我们将它style从一个简单的对象更改为一个返回对象的函数。
- 我们通过查看传递给样式函数的isActive值来更改链接的颜色。NavLink
四、嵌套路由的使用,父子路由,以及父组件默认路由【Outlet】
Route 支持嵌套 Route
- 它嵌套了 URL
("/" + "expenses"和"/" + "invoices")
- 当子路由匹配时,它将嵌套 UI 组件以进行共享布局:
4.1 路由文件设置
import { render } from "react-dom";
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";
const rootElement = document.getElementById("root");
render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />} />
</Route>
</Routes>
</BrowserRouter>,
rootElement
);
4.2 父组件需要使用 Outlet 来展示子组件的ui
类似于 vue-router 中的 router-view
import { Outlet, Link } from "react-router-dom";
export default function App() {
return (
<div>
<h1>Bookkeeper</h1>
<nav
style={{
borderBottom: "solid 1px",
paddingBottom: "1rem",
}}
>
<Link to="/invoices">Invoices</Link> |{" "}
<Link to="/expenses">Expenses</Link>
</nav>
{/* 这里是渲染子路由组件的地方,类似于 vue-router 中的 router-view */}
<Outlet />
</div>
);
}
4.3 父组件的默认组路由【索引路由 Index Routes】
注意它有
indexprop
而不是a path
。那是因为索引路由共享父路径。这就是重点——它没有路径。也许你还在摸不着头脑。我们尝试通过几种方式来回答“什么是索引路由?”这个问题。希望其中一根适合您:
- 索引路由在父路由路径的
父路由出口
中呈现。- 当
父路由匹配
但其他子路由都不匹配
时,索引路由匹配。索引路由
是父路由
的默认子路由
。- 当用户尚未单击导航列表中的一项时,会呈现索引路由。
<Routes>
<Route path="/" element={<App />}>
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />}>
<Route
index
element={
<main style={{ padding: "1rem" }}>
<p>Select an invoice</p>
</main>
}
/>
<Route path=":invoiceId" element={<Invoice />} />
</Route>
<Route
path="*"
element={
<main style={{ padding: "1rem" }}>
<p>There's nothing here!</p>
</main>
}
/>
</Route>
</Routes>
五、重定向路由【*】
在这里"*
"有特殊的含义。只有在没有其他路由匹配时才会匹配。
<Routes>
<Route path="/" element={<App />}>
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />} />
<Route
path="*"
element={
<main style={{ padding: "1rem" }}>
<p>There's nothing here!</p>
</main>
}
/>
</Route>
</Routes>
六、读取 URL 参数(不常用)
获取query参数,来自URL的参数。
6.1 router 文件定义
<Routes>
<Route path="/" element={<App />}>
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />}>
<Route path=":invoiceId" element={<Invoice />} />
</Route>
<Route
path="*"
element={
<main style={{ padding: "1rem" }}>
<p>There's nothing here!</p>
</main>
}
/>
</Route>
</Routes>
6.2 跳转 Link 定义
<Link
to={`/invoices/${invoice.number}`}
key={invoice.number}
>
{invoice.name}
</Link>
6.3 使用 useParams 获取参数
:invoiceId -> params.invoiceId
import { useParams } from "react-router-dom";
export default function Invoice() {
let params = useParams();
return <h2>Invoice: {params.invoiceId}</h2>;
}
七、读取搜索参数 【useSearchParams】
搜索参数类似于 URL 参数,但它们位于 URL 中的不同位置。它们不是位于由 分隔的普通 URL 段中/,而是位于 . 之后的末尾
?
。您已经在网络上看到过它们,例如"/login?success=1"
或"/shoes?brand=nike&sort=asc&sortby=price"
。
- setSearchParams()将?filter=…搜索参数放入 URL 并重新呈现路由器。
- useSearchParams现在返回a作为其值之一URLSearchParams。“filter”
- 我们将输入的值设置为过滤器搜索参数中的任何内容(就像useState但在URLSearchParams 中!)
- 我们根据过滤器搜索参数过滤我们的数据列表。
import {
NavLink,
Outlet,
useSearchParams,
} from "react-router-dom";
import { getInvoices } from "../data";
export default function Invoices() {
let invoices = getInvoices();
let [searchParams, setSearchParams] = useSearchParams();
return (
<div style={{ display: "flex" }}>
<nav
style={{
borderRight: "solid 1px",
padding: "1rem",
}}
>
<input
value={searchParams.get("filter") || ""}
onChange={(event) => {
let filter = event.target.value;
if (filter) {
setSearchParams({ filter });
} else {
setSearchParams({});
}
}}
/>
{invoices
.filter((invoice) => {
let filter = searchParams.get("filter");
if (!filter) return true;
let name = invoice.name.toLowerCase();
return name.startsWith(filter.toLowerCase());
})
.map((invoice) => (
<NavLink
style={({ isActive }) => ({
display: "block",
margin: "1rem 0",
color: isActive ? "red" : "",
})}
to={`/invoices/${invoice.number}`}
key={invoice.number}
>
{invoice.name}
</NavLink>
))}
</nav>
<Outlet />
</div>
);
}
八、【useLocation】 获取路由相关信息
8.1 用法 类似于 【useSearchParams】
import { useLocation, NavLink } from "react-router-dom";
function QueryNavLink({ to, ...props }) {
let location = useLocation();
return <NavLink to={to + location.search} {...props} />;
}
{
pathname: "/invoices",
search: "?filter=sa",
hash: "",
state: null,
key: "ae4cz2j"
}
8.2 【useSearchParams】
function BrandLink({ brand, ...props }) {
let [params] = useSearchParams();
let isActive = params.getAll("brand").includes(brand);
return (
<Link
style={{ color: isActive ? "red" : "" }}
to={`/shoes?brand=${brand}`}
{...props}
/>
);
}
九、函数式编程
9.1 示例代码
import {
useParams,
useNavigate,
useLocation,
} from "react-router-dom";
import { getInvoice, deleteInvoice } from "../data";
export default function Invoice() {
let navigate = useNavigate();
let location = useLocation();
let params = useParams();
let invoice = getInvoice(parseInt(params.invoiceId, 10));
return (
<main style={{ padding: "1rem" }}>
<h2>Total Due: {invoice.amount}</h2>
<p>
{invoice.name}: {invoice.number}
</p>
<p>Due Date: {invoice.due}</p>
<p>
<button
onClick={() => {
deleteInvoice(invoice.number);
navigate("/invoices" + location.search);
}}
>
Delete
</button>
</p>
</main>
);
}