这一篇文章的重点在于将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传参 */}<Linkto="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"));