为什么
一般来说,web系统需要多个页面,如果是单个页面的话,太复杂。这就像所有逻辑写在一个函数中,维护困难。那多页面就需要用路由来管理。路由是个通用概念,可以理解为网址。但是是业务上的页面,从技术上还是react的组件。
是什么
React Router 是一个流行的用于构建单页应用程序的路由库。它提供了一组组件,可以帮助我们在 React 应用中实现页面间的导航和路由管理。本文档将介绍 React Router 的使用方法和常见的功能。
怎么用
安装
首先,我们需要使用 npm 或者 yarn 来安装 React Router:
$ npm install react-router-dom
# 或者
$ yarn add react-router-dom
基本用法
BrowserRouter
在你的应用中引入 React Router,然后使用 BrowserRouter 组件包裹你的应用根组件:
import { BrowserRouter } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
{/* Your app code here */}
</BrowserRouter>
);
}
Route
接下来,你可以使用 Route 组件来定义路由规则和对应的组件:
import { Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</BrowserRouter>
);
}
在上面的示例中,我们定义了两个路由规则:
- / 路径对应的组件是 Home
- /about 路径对应的组件是 About 当用户访问不同的路径时,React Router 将会渲染对应的组件。
嵌套路由
React Router 还支持嵌套路由,即在一个组件中定义子路由规则。
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users" element={<Users />}>
<Route path="/" element={<UserList />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
在上面的示例中,我们定义了三个顶层路由:/、/about 和 /users。其中,/users 路径下又有两个子路由:/ 和 /:id。当用户访问不同的路径时,React Router v6 会根据路由配置自动匹配并渲染相应的组件。
注意,在嵌套路由中,父级路由组件(如 /users)需要在其 element 属性中设置一个组件,以便为嵌套的子路由提供一个渲染容器。
此外,你也可以使用 Outlet
组件来渲染嵌套的子路由:
import { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users">
<Route index element={<UserList />} />
<Route path=":id" element={<UserProfile />} />
<Outlet />
</Route>
</Routes>
</BrowserRouter>
);
}
在上面的示例中,我们使用 Outlet 组件来渲染嵌套的子路由。<Outlet />
会根据访问的 URL 渲染匹配的路由组件。
路由参数
有时候我们需要从 URL 中提取参数,以便在组件中使用。React Router 提供了 useParams 钩子来实现这个功能。
import { useParams } from 'react-router-dom';
function User() {
const { id } = useParams();
return <div>User ID: {id}</div>;
}
在上面的例子中,我们定义了一个 /user/:id
的路由规则,其中 :id 表示一个动态的参数。当用户访问 /user/123
时,useParams 钩子会返回 { id: '123' }
。
路由跳转
React Router 提供了一些组件来实现导航功能,比如链接 (Link) 和重定向 (Redirect)。
import { Link, Redirect } from 'react-router-dom';
function Navigation() {
return (
<div>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Redirect to="/login" />
</div>
);
}
编程式导航
当使用 React Router 进行编程式导航时,我们可以使用 history
对象来实现。history
对象提供了一些方法,可以在代码中进行导航操作。
首先,我们需要使用 useHistory
钩子来获取 history
对象:
import { useHistory } from 'react-router-dom';
function MyComponent() {
const history = useHistory();
// 导航到指定路径
const navigateTo = (path) => {
history.push(path);
};
return (
<div>
<button onClick={() => navigateTo('/about')}>Go to About</button>
</div>
);
}
在上面的例子中,我们使用 useHistory
钩子获取了 history
对象,并定义了一个 navigateTo
函数,该函数接受一个路径参数,并通过 history.push()
方法将用户导航到指定路径。
我们还可以使用 history.replace()
方法进行替换式导航,该方法不会在浏览器历史记录中创建新的条目
import { useHistory } from 'react-router-dom';
function MyComponent() {
const history = useHistory();
// 替换当前路径
const replacePath = (path) => {
history.replace(path);
};
return (
<div>
<button onClick={() => replacePath('/contact')}>Go to Contact</button>
</div>
);
}
除了使用 push 和 replace 方法导航之外,我们还可以使用其他方法来控制浏览器历史记录,比如 go、goBack 和 goForward:
import { useHistory } from 'react-router-dom';
function MyComponent() {
const history = useHistory();
// 后退
const goBack = () => {
history.goBack();
};
// 前进
const goForward = () => {
history.goForward();
};
// 跳转到指定历史记录位置
const goTo = (n) => {
history.go(n);
};
return (
<div>
<button onClick={goBack}>Go Back</button>
<button onClick={goForward}>Go Forward</button>
<button onClick={() => goTo(-2)}>Go Back 2 steps</button>
</div>
);
}
通过使用这些方法,我们可以在 React 应用中进行编程式导航,根据需要控制用户的浏览器行为。
路由守卫
当使用 React Router 构建应用程序时,有时我们需要在导航发生之前或之后执行一些逻辑操作。 不同于Vue-Router,React Router 没有提供相关的回调和方法。 得在应用中,自己实现。比如before场景:
import { Route, useHistory } from 'react-router-dom';
const MyComponent = () => {
const history = useHistory();
const beforeGuard = () => {
// 在导航之前执行的逻辑
if (!isLoggedIn) {
// 如果用户未登录,则跳转到登录页面
history.push('/login');
}
retun <User />;
};
return (
<Route path="/profile" render={beforeGuard} />
);
}
after场景,可以在 componentDidMount
或者 useEffect
中实现;leave场景,可以在componentWillUnmount
或者 useEffect
中实现。
useRoutes
useRoutes是和Route 组件功能相同的官方hook。Route 组件使用元素定义路由和组件,useRoutes使用JavaScript对象来定义和管理路由。
假设我们要设计一个博客系统,涉及到的页面及其路由如下:demo和代码地址
页面 | 路由 | Layout | |
---|---|---|---|
首页 | / | MainLayout | |
登录 | /register | ||
注册 | /login | ||
404 | |||
管理页面 | 我的博客 | /manage/list | ManageLayout |
收藏博客 | /manage/star | ||
博客回收站 | /manage/trash | ||
博客详情 | 编辑博客 | /blog/edit/:id | BlogLayout |
博客统计 | /blog/stat/:id |
使用如下:
首先,我们定义路由管理文件router.js:
import { createBrowserRouter } from "react-router-dom";
const router = createBrowserRouter([
{
// 根路由
path: "/",
element: <MainLayout />,
children: [
{
path: "/",
element: <Home />
},
{
path: "login",
element: <Login />
},
{
path: "register",
element: <Register />
},
{
path: "manage",
element: <ManageLayout />,
children: [
{
// path: "list",
// 这个属性表示默认路由,写了这个就不能写path属性
index: true,
element: <List />
},
{
path: "star",
element: <Star />
},
{
path: "trash",
element: <Trash />
}
]
},
{
path: "*",
element: <NotFound />
}
]
},
{
path: "blog",
element: <BlogLayout />,
children: [
{
path: "edit/:blogId",
element: <EditBlog />
},
{
path: "stat/:blogId",
element: <BlogStat />
}
]
}
]);
export default router;
在上面的示例中,routeConfig 数组中的每个对象都包含 path 和 element 属性,分别表示路径和要渲染的组件。如果有嵌套路由,则可以在对应的对象中使用 children 属性来定义子路由。
注意:index: true 和 path: "*"
- index: true 属性表示默认路由,写了这个就不能写path属性
- path: "*" 表示所有匹配,没有命中任何规则时显示的组件,一般用来处理错误路由
- Outlet 其实就是占位,类似于vue中的slot或者router-view 然后,我们在应用入口中引入router:
import "./styles.css";
import { RouterProvider } from "react-router-dom";
import router from "./router";
export default function App() {
return (
<div className="App">
<RouterProvider router={router} />
</div>
);
}