这一篇文章的重点在于将React关于路由的问题都给搞清楚。
一个路由就是一个映射关系,key:value。key是路径,value 可能是function或者component。
安装react-router-dom包使用路由服务,我这里想要用的是6版本的包,因此后面加”@6"
npm install react-router-dom@6
首先要介绍的是HashRouter和BrowserRouter,这两个组件的作用在于提供一个路由环境,方便在后续React应用程序中使用路由服务。
一、HashRouter和BrowserRouter之间的区别
HashRouter和BrowserRouter之间的区别主要表现在两个方面,一个是表现形式,一个是工作原理。
1. URL表现形式
BrowserRouter的url没有#符号。例如:http://example.com/about
HashRouter的url中包含了一个#符号,该符号后面是hash部分,不会发送到服务器。 例如:http://example.com/#/about
2. 工作原理
对于HashRouter来说,它不需要在服务器中对相应的路由进行配置,它监听hashchange事件,根据hash的变化渲染对应的组件。
对于BrowserRouter来说,他使用Html5中的History api来实现路由。因为不是hash段所以会向服务器端发送请求,需要在服务器中进行相应的配置,均返回index.html网站即可。
跟这两个类似的还有一个MemoryRouter,这里暂不介绍。
上述内容是用来包裹react应用的,使React应用支持路由服务
二、NavLink、Link、Routes和Route
Routes是路由器组,Route必须要用它包裹才能用,Routes的作用是包括Route包裹路由,Route的作用是将组件放在所要定义的位置。
<Routes>
<Route path="/home" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/" element={<Navigate to="/home" />} />
</Routes>
NavLink与Link按钮之间的区别在于,如果NavLink被点击之后会增加一个active的类名,可以被设置相应的样式,而link没有。
Link与NavLink的作用就相当于是人告诉界面我要显示哪个组件,然后Route的作用是去找组件。
<div>
<NavLink to="/about">About</NavLink>
<NavLink to="/home">Home</NavLink>
</div>
上述内容如下图所示。
三、 useRoutes、路由表、Outlet
路由表
RouteObject
目前在使用的过程中我只使用了path、children、caseSensitive、element四个基本的配置项。
Index.tsx中定义路由表
import React from "react";
import About from "../components/About";
import Home from "../components/Home";
import News from "../components/News";
import Message from "../components/Message";
import { Navigate } from "react-router-dom";
const routes: any[] = [
{
path: "/about",
element: <About />,
},
{
path: "/home",
element: <Home />,
children: [
{
path: "news",
element: <News />,
},
{
path: "message",
element: <Message />,
},
],
},
{
path: "/",
element: <Navigate to="/about" />,
},
];
export default routes;
app中引入路由表并使用
import React from "react";
import routes from "./router/index";
import { NavLink, useRoutes } from "react-router-dom";
function App() {
const element = useRoutes(routes);
return (
<div className="App">
<div>
<NavLink to="/about">About</NavLink>
<NavLink to="/home">Home</NavLink>
</div>
{element}
</div>
);
}
export default App;
子路由部分用标签占位,定义插入位置
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Home() {
return (
<div>
<h2>Home组件内容</h2>
<div>
<NavLink to="news">新闻</NavLink>
<NavLink to="message">信息</NavLink>
</div>
<Outlet />
</div>
);
}
上述定义均没有涉及样式,样式是在组件里或者html部分自行定义的。
四、路由传参方式
路由传参方式有三种,
1. 一个是useParams接收参数,接收的是路径上的参数,例如:/index/id,接收的是这个id;
首先,是设置路由表的地方跟别的有点区别,因为它是接收路径上的参数。
//在path地方需要进行特殊定义
{
path: "message",
element: <Message />,
children: [
{
path: "detail/:id/:title/:content",
element: <Detail />,
},
],
},
其次,传递方式。
import React, { useState } from "react";
import { Link, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: "001", title: "消息1", content: "锄禾日当午" },
{ id: "002", title: "消息2", content: "汗滴禾下土" },
{ id: "003", title: "消息3", content: "谁知盘中餐" },
{ id: "004", title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((m) => {
// const url = "detail?id=" + m.id + "&title=" + m.title + "&content=" + m.content;
return (
<li key={m.id}>
{/* 模版字符串传参数*/}
<Link to={`/home/message/detail/${m.id}/${m.title}/${m.content}`}>
{m.title}
</Link>
</li>
);
})}
</ul>
<hr />
{/* 指定子组件所放置的位置 */}
<Outlet />
</div>
);
}
接收参数,useParams
import React from "react";
import { useParams } from "react-router-dom";
export default function Detail() {
const { id, title, content } = useParams();
return (
<div>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{content}</p>
</div>
</div>
);
}
useParams()这个方法只用来接收参数。
2. 第二种是接收url中传递的参数,使用useLocation,例如:/index?id=5,接收的是这个id;
//传递参数的方式
<div>
<ul>
{messages.map((m) => {
const url =
"detail?id=" + m.id + "&title=" + m.title + "&content=" + m.content;
return (
<li key={m.id}>
<Link to={url}>{m.title}</Link>
</li>
);
})}
</ul>
<hr />
{/* 指定子组件所放置的位置 */}
<Outlet />
</div>
//上面传递参数的方式也可以直接用模版字符串来传参
<Link to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`} >
需要使用location对象来接收参数。
//接收参数的方式
import React from "react";
import { useLocation } from "react-router-dom";
export default function Detail() {
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const [id, title, content] = [
queryParams.get("id"),
queryParams.get("title"),
queryParams.get("content"),
];
return (
<div>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{content}</p>
</div>
</div>
);
}
下面是打印出来的location,可以看到下面接收的对象中有哪些数据。
3. 第三种是接收state传递的参数,使用useState.
传递参数
import React, { useState } from "react";
import { Link, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: "001", title: "消息1", content: "锄禾日当午" },
{ id: "002", title: "消息2", content: "汗滴禾下土" },
{ id: "003", title: "消息3", content: "谁知盘中餐" },
{ id: "004", title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((m) => {
// const url = "detail?id=" + m.id + "&title=" + m.title + "&content=" + m.content;
return (
<li key={m.id}>
{/* 使用state传参 */}
<Link
to="detail"
state={{ id: m.id, title: m.title, content: m.content }}
>
{m.title}
</Link>
</li>
);
})}
</ul>
<hr />
{/* 指定子组件所放置的位置 */}
<Outlet />
</div>
);
}
接收参数,上面我们在location对象中看到了state,我们就是接收location对象中的state。
import React from "react";
import { useLocation, useParams } from "react-router-dom";
export default function Detail() {
const location = useLocation();
const { id, title, content } = location.state;
console.log(useParams());
return (
<div>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{content}</p>
</div>
</div>
);
}
useMatch() api返回当前匹配结果。
console.log(useMatch("/home/message/detail"));