React Router,简单来说,是一个帮助处理React应用程序中导航和路由的库。它是用于管理React中路由的最流行的路由工具。如果你对路由的概念不熟悉,可以将其视为在网站的不同部分之间导航的过程。例如,当你进入网站的“联系我们”部分时,你已经成功进行了一次路由过程。本文将为您提供有关React Router的所有细节,以便您可以充分利用它。
如果你对React Router还不熟悉,你可能习惯使用普通的链接(a标签)在你的应用程序中进行导航。然而,当你想在导航时保留应用程序的当前状态时,就会出现问题。不幸的是,普通的链接通常会触发页面刷新来显示组件,从而破坏用户体验。这就是React Router的用武之地。
React Router允许您在应用程序中定义不同的路由,并将它们链接到各自的组件,而无需重新加载页面。这种方法使得React Router能够轻松更新页面上的内容,并使网站感觉像一个原生应用程序。
使用React Router还有其他好处,比如创建复杂的导航、无缝的页面导航结构以及对动态URL的支持。
设置环境
要理解React Router的工作原理,最好的方法之一是构建一个简单的网站。因此,让我们构建一个小型的历史网站,不要太复杂。
所以,让我们准备好一切开始使用React Router所需的东西。
安装React:有几种方法可以做到这一点,但让我们选择最简单的方法:create-react-app(CRA)。通过代码编辑器终端安装React,运行以下命令:
代码语言:javascript复制npx create-react-app history-app
然后,通过运行cd history-app导航到创建的React应用程序。
- 安装React Router:要在React网站中安装react-router包,请在终端中运行以下命令:
npm install react-router-dom
这个命令允许你安装React Router,一个必要的包。
完成后,您可以通过运行npm start来启动React应用程序。就是这样!React和React Router已经准备好使用了。
让我们添加一些React组件,以便在历史应用程序上获得一些虚拟内容。您只需将其复制并粘贴到App.js中,即默认的应用程序组件。
代码语言:javascript复制export default function App() {
return (
<>
<Home />
</>
);
}
function Home() {
return (
<div>
<h1>The Paradise of History</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nihil vero
laudantium repella
</p>
</div>
);
}
function Eras() {
return (
<div>
<h1>The Eras of Time</h1>
<ul>
<li>
<a href="/">Medieval</a>
</li>
<li>
<a href="/">Digital</a>
</li>
</ul>
</div>
);
}
运行后的效果
理解路由概念
在我们继续之前,让我们快速了解一些React Router中的关键概念:
History Stack:React Router智能地使用HTML5 History API来跟踪用户的导航历史。当用户访问一个新的URL时,React Router将该URL推送到历史堆栈中。当用户导航到其他URL时,它们也会被推送到堆栈中。这就是React Router在不刷新页面的情况下来回导航路由的方式。
Location:这指的是在浏览网站时当前所在的URL。它是历史堆栈中的顶级URL,以及React Router如何动态更改显示的内容以匹配正确的URL。
在一些浏览器中,比如Chrome,你可以点击并长按“返回”按钮来查看历史记录中所有的URL列表。
浏览器路由器及其用途
众所周知,React使用组件和钩子,React Router也是如此。而React Router提供的一个关键组件是。
就像body元素是网站的骨干一样,BrowserRouter 对于 React Router 也是如此。它为网站内所有可能的路由提供了基础。
注意:BrowserRouter使用HTML5 History API来操作浏览器的URL,并将其与当前显示的页面保持同步。
BrowserRouter可以放置在应用程序的任何位置,但通常情况下,您会希望将BrowserRouter放置在组件树的顶部,以包裹整个应用程序的组件。
现在,回到构建我们简单的历史网站的过程中。为了实现BrowserRouter,将整个App组件包裹在其中。要做到这一点,请转到index.js文件:
代码语言:javascript复制import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
通过 <BrowserRouter /> App 组件,路由功能在 App 组件中的所有组件中都可用。
关于BrowserRouter的内容就这些了,我们继续吧。
值得注意的是,还有其他类似的组件可用,比如 MemoryRouter、StaticRouter 等等。
使用 Routes 和 Route
要完全掌握React Router中的 Routes 组件的作用,首先我们需要了解 Route 的作用。
Route
简单来说, Route 定义了一个特定的URL路径,并指向在访问该URL路径时应该渲染的组件。
路由组件有两个主要属性:
Path:此属性接受一个字符串,用于指定 Route 的路径。例如,如果有一个 Route ,其 path 设置为 "/eras" ,每当URL变为 https://historyApp.com/eras 时,将触发此 Route 。
Element:当 path 属性中的路径被访问时,该属性被分配给要渲染的React组件。因此,如果访问 /eras 路径,则 <Eras /> 组件将在页面上呈现。
这里是一个代码示例:
代码语言:javascript复制<Route path='/eras' element={<Eras />} />
Routes
Routes 是 Route 组件的容器组件。它负责检查当前URL位置,并将其与子 Route 组件中指定的路径进行比较,以找到匹配项。
在 Routes 内,您可以嵌套所有的 Route 组件,然后在浏览网站时, Routes 会获取当前的URL,并将其与每个子路由组件进行匹配,以找到与之对应的最佳组件。
因此,在历史应用程序中设置 Routes 和 Route 的步骤如下:
代码语言:javascript复制import { Routes, Route } from 'react-router-dom';
export default function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/eras" element={<Eras />} />
</Routes>
);
}
这段代码中:
- 首先从 react-router-dom 包中导入 Routes 和 Route 组件。
- 然后,在 App 组件内部, Routes 组件限制了不同的 Route 组件。
- 第一个路由的路径设置为("/"),当访问时将渲染 Home 组件。这个默认路由将始终在访问根URL时渲染。
- 该 /eras 路由与 Eras 组件相关联。这意味着每当URL路径与 /eras 匹配时,将显示 <Eras /> 内容。
当您在地址栏中的根URL后添加 /eras 时,React Router使用 Routes 组件来匹配具有路径设置为 /eras 的确切 Route 。一旦找到,将渲染在匹配的 Route 的 element 属性中定义的组件;在这种情况下,是 <Eras /> 组件。
404 页面
404错误是一个HTTP状态码,当请求的资源或页面无法找到时会显示出来。这可能发生在用户输入了一个不存在的URL时。
React Router 包含了一种处理 404 错误的方式,当访问一个未定义的网址时,会渲染一个自定义组件。
要处理React Router中的404错误,请创建一个 route ,将其 path 属性设置为 * ,并将其 element 属性设置为应该呈现的错误组件。
可以这样实施:
首先,让我们创建一个错误404组件
代码语言:javascript复制function Error404() {
return (
<div>
<h1>404 — Page Not Found</h1>
<a href="/">Take me back!</a>
</div>
);
}
然后创建一个 route 来渲染 <Error404 />.
代码语言:javascript复制export default function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/eras" element={<Eras />} />
{/* 404 page */}
<Route path="*" element={<Error404 />} />
</Routes>
);
}
有了这个设置,每当访问一个不存在的URL时,React Router会自动使用 route 组件,并将 path 设置为 * ,然后渲染其元素,即 Error404 组件。
现在,我们可以放心地确保网站能够处理任何意外的URL。
路由之间的连接
到目前为止,我们只讨论了如何通过手动在地址栏中输入URL来访问路由。然而,这种方式并不理想,因为用户必须记住每个页面的确切URL才能访问。
a 标签通常用于解决这个问题,但它有一些限制。为了绕过这些限制,React Router使用 Link 组件。
在React Router中, Link 是路由导航的主要方式。链接组件在底层使用 a 标签,但通过阻止默认页面重新加载来增强它。相反, Link 将其 to 属性中的URL推送到历史堆栈,然后 routes 组件找到具有相同URL的匹配 route 并显示相关组件。
React Router使用 Link 组件而不是 a 标签,因为 Link 被设计用于防止页面重新加载,保留应用程序状态,并在路由之间提供无缝导航。
这是在历史网站中使用 Link 的方法。前往 App.js 并创建一个导航组件:
代码语言:javascript复制import { Link } from "react-router-dom";
function Nav() {
return (
<ul className='nav'>
<li>
<Link to='/'>Home</NavLink>
</li>
<li>
<Link to='/eras'>Eras</NavLink>
</li>
</ul>
);
}
首先从 react-router-dom 导入 Link 组件。然后,创建一个功能组件 Nav ,用作历史网站的导航。
这个 Nav 组件遵循了典型导航菜单的结构;只是使用了 Link 组件而不是 a 标签。
每个 <Link /> 都有一个特定的路径分配给 to 属性;这为 Link 设置了目标路由。因此,当点击任何这些链接时,React Router会从 to 属性获取URL,匹配正确的 route 路径,并渲染指定的组件。
由于 Nav 组件应该在所有页面上可见,让我们将其放置在 App 组件的顶部:
代码语言:javascript复制export default function App() {
return (
<>
<Nav />
<Routes>
<Route path='/' element={<Home />} />
<Route path='/eras' element={<Eras />} />
<Route path='*' element={<Error404 />} />
</Routes>
</>
);
}
我们还可以给它添加一些简单的样式来增加吸引力:App.css
代码语言:javascript复制a {
text-decoration: none;
color: inherit;
}
a:hover {
color: #e32a30;
}
.nav {
list-style: none;
display: flex;
width: 500px;
justify-content: space-around;
align-items: center;
font-size: 1.1rem;
font-weight: bold;
}
NavLink 与 Link 的不同
React Router有一个叫做 NavLink 的组件。它类似于 Link ,但主要用于处理菜单导航链接,不同于 Link 组件,后者可用于任何类型的链接。
NavLink 和 Link 之间的主要区别是 NavLink 能够检测自身是否处于活动状态。当 NavLink 检测到自身处于活动状态时,默认会给其组件添加一个 active 类。
由于历史网站中存在导航菜单,让我们将 Link 组件更新为 NavLink
代码语言:javascript复制import { Link, NavLink } from "react-router-dom";
function Nav() {
return (
<ul className='nav'>
<li>
<NavLink to='/'>Home</NavLink>
</li>
<li>
<NavLink to='/eras'>Eras</NavLink>
</li>
</ul>
);
}
active 类可以使用CSS进行自定义。前往 App.css 进行修改:
代码语言:javascript复制.active {
color: #e32a30;
}
总的来说, NavLink 在创建导航菜单链接时比 Link 组件更强大。
嵌套路由
在React Router中,嵌套可以被视为在路由之间建立父子连接。这可以用来组织共享相同URL路径的路由。
嵌套路由使用一个 Route 组件作为父路由,另一个 Route 组件用于定义父路由内的子路由。因此,只有在父路由上时才能渲染子路由。
在历史网站上,可以在时代部分找到“中世纪(Medieval)”和“数字化(Digital)”这两个可用的时代类别。因此,要访问这些时代的详细信息,我们可以将它们嵌套在 /eras 路径中。
让我们将这个功能添加到历史网站上:
创建“Medieval”和“Digital”组件:
代码语言:javascript复制function MedievalEra() {
return (
<div>
<hr />
<h3>The Medieval Era</h3>
<p>Lorem ipsum dolor sit amet.</p>
</div>
);
}
function DigitalEra() {
return (
<div>
<hr />
<h3>The Digital Era</h3>
<p>Lorem ipsum dolor sit amet.</p>
</div>
);
}
转到 App 组件,并在 /eras 路由内创建嵌套路由:
代码语言:javascript复制export default function App() {
return (
<>
<Nav />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/eras" element={<Eras />}>
<Route path="medieval" element={<MedievalEra />} />
<Route path="digital" element={<DigitalEra />} />
</Route>
<Route path="*" element={<Error404 />} />
</Routes>
</>
);
}
此时,导航到 /eras/medieval 或 /eras/digital 应该分别呈现 <MedievalEra /> 和 <DigitalEra /> 组件。然而,它不会按预期呈现。
这是因为React Router不知道如何放置这些嵌套组件。为了解决这个问题,React Router提供了一个名为 Outlet 的组件,可以明确指出嵌套路由组件应该放置在哪里。
导入 Outlet 组件:
代码语言:javascript复制import { Outlet } from "react-router-dom";
将 Outlet 组件放置在 Eras 组件内部:
代码语言:javascript复制function Eras() {
return (
<div>
<h1>The Eras of Time</h1>
<ul>
<li>
<Link to="medieval">Medieval</Link>
</li>
<li>
<Link to="digital">Digital</Link>
</li>
</ul>
<Outlet />
</div>
);
}
在这段代码中,之前使用的 a 标签已被替换为 Link 组件,并将相应的路径放置在 to 属性中。
在此之后, <Outlet /> 组件将被放置在下方,因为这是嵌套路由组件将被渲染的位置。
嵌套路由有各种用途,比如层次化组织路由、代码效率、提高性能等。
动态路由与useParams
动态路由是一个概念,它允许您创建不是硬编码的路由,而是根据用户操作或数据生成的路由。
React Router使用 Route 组件和 useParams 钩子来处理动态路由。
设置动态路由时,在 route 组件的 path 属性中使用占位符(用冒号 : 表示)。
就像这样:
代码语言:javascript复制<Route path="/eras/:type" element={<EraType />} />
这里,对于 Route 的占位符是 : type ,它表示 type 参数的值将会动态生成。
React Router 提供了一个叫做 useParams 的钩子,用于有效处理动态路由。
基本上, useParams hook 返回一个包含来自 Route 组件的动态值的对象,该值可以在负责渲染动态内容的组件中使用。
让我们看看它是如何工作的:
代码语言:javascript复制import { useParams } from "react-router-dom";
function EraType() {
const { type } = useParams();
return (
<div>
<hr />
<h3>The {type} Era</h3>
</div>
);
}
现在更新在 /eras 中找到的路由,以包括动态路由:
代码语言:javascript复制export default function App() {
return (
<>
<Nav />
<Routes>
<Route path='/' element={<Home />} />
<Route path='/eras' element={<Eras />}>
<Route path='medieval' element={<MedievalEra />} />
<Route path='digital' element={<DigitalEra />} />
{/* Dynamic route */}
<Route path=':type' element={<EraType />} />
</Route>
<Route path='*' element={<Error404 />} />
</Routes>
</>
);
}
有了这个动态 Route ,当你在 /eras 路由内导航时,像 /eras/ancient 这样。值“ancient”是动态路径,并且可以通过从 useParams 提取的 type 变量进行访问。
由于嵌套的路由结构, <Eras /> 组件内的 <EraType /> 被渲染出来。
这只是 useParams 的一个基本用例;这个钩子可以用于其他方式,比如从API中获取类似的动态数据。
使用useRoutes钩子
React Router 提供的另一个钩子是 useRoutes 钩子。
这个钩子只是React Router中用于结构化 Routes 和 Route 的另一种方式。它的工作原理是:不使用React组件(JSX)的形式,而是使用JavaScript对象。
在 App.js 中,这是我们如何构建 Routes 和 Route 组件的结构:
代码语言:javascript复制export default function App() {
return (
<>
<Nav />
<Routes>
<Route path='/' element={<Home />} />
<Route path='/eras' element={<Eras />}>
<Route path='medieval' element={<MedievalEra />} />
<Route path='digital' element={<DigitalEra />} />
<Route path=':type' element={<EraType />} />
</Route>
<Route path='*' element={<Error404 />} />
</Routes>
</>
);
}
现在,通过使用 useRoutes 钩子,代码可以重构如下:
代码语言:javascript复制import { useRoutes } from 'react-router-dom';
export default function App() {
const routes = useRoutes([
{
path: "/",
element: <Home />,
},
{
path: "/eras",
element: <Eras />,
children: [
{
path: "medieval",
element: <MedievalEra />,
},
{
path: "digital",
element: <DigitalEra />,
},
{
path: ":type",
element: <EraType />,
},
],
},
{
path: "*",
element: <Error404 />,
},
]);
return (
<>
<Nav />
{routes}
</>
);
}
useRoutes 钩子从 react-router-dom 导入。然后,一个路由对象数组被传递给 useRoutes 。每个路由对象都有一个 path 和 element 属性,用于指定路径和在路由匹配时应该渲染的组件。
所以,在 useRoutes 钩子或 Routes 和 Route 组件之间的选择归结为个人偏好。选择最适合你风格的那个。
结束
总之,学习React Router是React开发者应该迈出的重要一步。通过使用这个工具,在应用中管理路由导航和创建良好结构化的路由系统变得轻而易举。