前端路由一般通过HistoryAPI或是路径Hash实现,React没有内置前端路由相关的功能,但我们可以集成react-router
这个库来实现,目前react-router
最新版本是v6.4
,新版本的一些API发生了变化,我们将以最新版本进行介绍。
执行以下命令安装react-router
库。
npm install react-router-dom@6 --save
注意:我们安装的包名为react-router-dom
,除此之外还有react-router
、react-router-native
这两个包,但它们包含了React Native相关的支持,我们在浏览器环境中不需要使用,因此仅安装react-router-dom
即可。
react-router
提供了如下几个基础组件用于构建路由:
BrowserRouter:BrowserRouter组件一般位于应用的最外层,它基于浏览器的HistoryAPI和React Context实现,提供了识别路由并改变其内部渲染组件的功能。
HashRouter:同BrowserRouter,但路由使用URL的Hash实现。
Route:Route用于定义访问路径和组件的关系,访问一个路径时,对应路径的组件会渲染出来。
Routes:Routes用于包裹若干个Route组件,它类似于switch...case...
语句中switch
的作用。
Link:Link的作用类似于<a>
标签,用于实现跳转链接。实际上Link组件最终也会以<a>
标签形式渲染,但它们的功能有些区别,react-router
重写了它的默认逻辑,如果跳转的页面是Route路由中定义的,那么它只会改变页面上渲染的内容,而不会重新刷新页面。如果使用react-router
,我们就应该尽量使用Link组件而不是<a>
标签。
Redirect:前端路由重定向。重定向本身是后端的概念,指HTTP服务端返回301或302请求,告知客户端跳转到一个新的地址,Redirect组件的意义和Link组件类似,它能让前端路由重定向而不必请求服务端。
实际开发中,由于现代浏览器已经广泛支持HistoryAPI了,因此我们一般都选用BrowserRouter作为路由的实现方式。
下面例子代码中,我们使用BrowserRouter实现了前端路由,分别访问/a
、/b
、/c
地址会分别渲染A、B、C三个组件。
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import ComponentA from "./ComponentA";
import ComponentB from "./ComponentB";
import ComponentC from "./ComponentC";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/a" Component={ComponentA} />
<Route path="/b" Component={ComponentB} />
<Route path="/c" Component={ComponentC} />
</Routes>
</BrowserRouter>
</React.StrictMode>
);
下面代码中,我们使用Link组件实现路由跳转,点击后会跳转到组件B,我们可以和<a>
标签对比观察,Link组件跳转时页面是不会重新请求服务端加载的。
import { Link } from "react-router-dom";
const ComponentA = () => {
return (
<div>
<Link to="/b">ComponentB</Link>
</div>
);
};
export default ComponentA;
此外,我们也可以使用JavaScript代码进行手动跳转。React Router中手动跳转需要使用useNavigate()
,这和原生客户端JavaScript中修改location.href
不同。
import { useNavigate } from "react-router-dom";
const ComponentA = () => {
const navigate = useNavigate();
return (
<div>
<button
onClick={() => {
navigate("/b");
}}
>
Button
</button>
</div>
);
};
export default ComponentA;
实现404页面功能很简单,我们指定一个*
路由,当其他路由都不匹配时就会渲染该路由指定的组件。
<BrowserRouter>
<Routes>
<Route path="/a" Component={ComponentA} />
<Route path="/b" Component={ComponentB} />
<Route path="/c" Component={ComponentC} />
<Route path="*" Component={NotFound} />
</Routes>
</BrowserRouter>;
代码中我们创建了一个NotFound
组件,其他路由都不匹配时就会渲染该组件。
react-router
中提供了Hooks函数,用来获取GET参数和路径参数。
对于URL中的GET参数(?
后面的参数),我们可以使用useSearchParams
进行解析。
import { useSearchParams } from "react-router-dom";
const ComponentA = () => {
const [searchParams] = useSearchParams();
return (
<div>
{searchParams.get("username")}
{searchParams.get("classId")}
</div>
);
};
export default ComponentA;
例子中我们获取了GET参数,并显示到页面上。
路由路径中我们可以使用冒号定义路径参数的占位符,形如/a/:id
,此时我们可以使用useParams
获取真实的路径参数。注意这回影响路由的匹配,形如/a/3
、/a/tom
会匹配/a/:id
,但/a
不会。如果希望参数的可选的,可以使用/a/:id?
的形式定义可选路径参数。
import { useParams } from "react-router-dom";
const ComponentA = () => {
const { id } = useParams();
return <div>{id}</div>;
};
export default ComponentA;
上面例子代码中我们获取了请求的路径参数并显示到页面上。
useLocation
可以解析整个路径信息,如果前面的几种取参数方式不能满足,我们也可以通过useLocation
手动解析参数。一个location对象的例子(这里用的是BrowserRouter
进行演示):
{
hash: "";
key: "jnvqdg";
pathname: "/a";
search: "";
state: undefined;
}
#
后面的值?
后面的字符串import { useLocation } from "react-router-dom";
const ComponentA = () => {
const { pathname, search, hash } = useLocation();
return (
<div>
{pathname}
{search}
{hash}
</div>
);
};
export default ComponentA;
上面例子代码中,我们从当前路径中解析出了pathname
、search
、hash
的值。