React Router 初学者完整指南(包括 Router Hooks)
最初发布在我的博客上
React 是一个用于构建用户界面的 JavaScript 库。我们还可以借助 React Router 扩展它,构建多页应用程序。React Router 是一个第三方库,支持 React 应用中的路由功能。
在本教程中,我们将介绍开始使用 React Router 所需了解的所有内容。
- 设置项目
- 什么是路由?
- 设置路由器
- 渲染路线
- 使用链接切换页面
- 传递路由参数
- 以编程方式导航
- 重定向到另一个页面
- 重定向至 404 页面
- 守卫路线
- 路由器钩子(useHistory、useParams、useLocation)
- 最后的想法
- 后续步骤
设置项目
为了能够继续操作,您需要通过在终端中运行以下命令来创建一个新的 React 应用程序:
npx create-react-app react-router-guide
然后,将这些代码行添加到App.js
文件中。
- 在
App.js
import React from "react";
import "./index.css"
export default function App() {
return (
<main>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</main>
);
}
// Home Page
const Home = () => (
<Fragment>
<h1>Home</h1>
<FakeText />
</Fragment>
);
// About Page
const About = () => (
<Fragment>
<h1>About</h1>
<FakeText />
</Fragment>
);
// Contact Page
const Contact = () => (
<Fragment>
<h1>Contact</h1>
<FakeText />
</Fragment>
);
const FakeText = () => (
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
)
然后,如果您准备好了,让我们首先回答一个重要问题:什么是路由?
什么是路由?
路由是向用户显示不同页面的能力。这意味着它允许通过输入 URL 或点击元素在应用程序的不同部分之间移动。
众所周知,React 默认不带路由。为了在项目中启用它,我们需要添加一个名为react-router 的库。
要安装它,您必须在终端中运行以下命令:
yarn add react-router-dom
或者
npm install react-router-dom
现在,我们已经成功安装了我们的路由器,让我们在下一节开始使用它。

设置路由器
为了在我们的 React 应用中启用路由,我们首先需要BrowserRouter
从导入react-router-dom
。
- 在
App.js
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router } from "react-router-dom";
export default function App() {
return (
<Router>
<main>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</main>
</Router>
);
}
它应该包含应用中所有需要路由的地方。这意味着,如果我们需要在整个应用中进行路由,就必须用 包裹上层组件BrowserRouter
。
顺便说一句,您不必BrowserRouter as Router
像我在这里一样重命名,我只是想保持内容可读。
仅一个路由器,没有太多作用,让我们在下一节中添加一条路由。
渲染路线
要渲染路由,我们必须Route
从路由器包中导入组件。
- 在
App.js
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route } from "react-router-dom";
export default function App() {
return (
<Router>
<main>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<Route path="/" render={() => <h1>Welcome!</h1>} />
</main>
</Router>
);
}
然后,将其添加到我们想要渲染内容的位置。该Route
组件有几个属性。但在这里,我们只需要path
和render
。
-
path
:路由的路径。这里我们用来/
定义首页的路径。 -
render
:每当到达路线时,它都会显示内容。在这里,我们将向用户呈现一条欢迎消息。
在某些情况下,提供这样的路线是完全没问题的,但想象一下当我们必须处理一个真正的组件时,使用render
可能不是正确的解决方案。
那么,我们该如何显示一个真正的组件呢?Route
组件有一个名为 的属性component
。
让我们稍微更新一下示例,看看它的实际效果。
- 在
App.js
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route } from "react-router-dom";
export default function App() {
return (
<Router>
<main>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<Route path="/" component={Home} />
</main>
</Router>
);
}
const Home = () => (
<Fragment>
<h1>Home</h1>
<FakeText />
</Fragment>
);
现在,我们的路线将加载组件,而不是呈现消息Home
。
为了充分发挥 React Router 的强大功能,我们需要创建多个页面和链接。我们已经创建好了页面(如果需要,也可以创建组件),现在,让我们添加一些链接,以便在页面之间切换。
使用链接切换页面
为了向我们的项目添加链接,我们将再次使用 React Router。
- 在
App.js
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
export default function App() {
return (
<Router>
<main>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</main>
</Router>
);
}
const Home = () => (
<Fragment>
<h1>Home</h1>
<FakeText />
</Fragment>
);
const About = () => (
<Fragment>
<h1>About</h1>
<FakeText />
</Fragment>
);
const Contact = () => (
<Fragment>
<h1>Contact</h1>
<FakeText />
</Fragment>
);
导入 之后Link
,我们需要稍微更新一下导航栏。现在, React Router
不再使用a
和 标签,而是使用和,这样就可以在页面之间切换而无需重新加载。href
Link
to
然后,我们需要添加两个新路线:About
并且Contact
如果您愿意的话能够在页面或组件之间切换。
现在,我们可以通过链接访问应用程序的不同部分。但是,我们的路由器存在一个问题,Home
即使我们切换到其他页面,该组件仍然会显示。
原因是 React Router 会检查path
定义的路由是否以 开头,/
如果是,就会渲染该组件。
这里,我们的第一个路由以 开头/
,因此Home
每次都会渲染该组件。
exact
但是,我们仍然可以通过向 中添加属性来更改默认行为Route
。
- 在
App.js
<Route path="/" exact component={Home} />
通过使用 更新Home
路线exact
,现在,只有当它与完整路径匹配时才会呈现它。
我们仍然可以增强它,通过包装我们的路由来Switch
告诉 React Router 一次只加载一个路由。
- 在
App.js
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
现在,我们有了新的链接,让我们使用它们来传递参数。
传递路由参数
为了在页面之间传递数据,我们必须更新我们的示例。
- 在
App.js
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
export default function App() {
const name = 'John Doe'
return (
<Router>
<main>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to={`/about/${name}`}>About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about/:name" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
</main>
</Router>
);
}
const Home = () => (
<Fragment>
<h1>Home</h1>
<FakeText />
</Fragment>
);
const About = ({match:{params:{name}}}) => (
// props.match.params.name
<Fragment>
<h1>About {name}</h1>
<FakeText />
</Fragment>
);
const Contact = () => (
<Fragment>
<h1>Contact</h1>
<FakeText />
</Fragment>
);
正如你所见,我们首先声明一个新的常量name
,它将作为参数传递给About
页面。然后,我们将其附加name
到相应的链接。
这样,我们现在必须About
通过调整其路径来更新路线以name
作为参数接收path="/about/:name"
。
现在,参数将作为 props 从About
组件接收,我们现在唯一要做的就是解构 props 并返回name
属性。顺便说一下,{match:{params:{name}}}
与 相同props.match.params.name
。
到目前为止,我们已经做了很多,但是,在某些情况下,我们不想使用链接在页面之间导航。
有时,我们必须等待操作完成后才能导航到下一页。

因此,让我们在下一节中处理该情况。
以编程方式导航
我们收到的道具有一些方便的方法可以用来在页面之间导航。
- 在
App.js
const Contact = ({history}) => (
<Fragment>
<h1>Contact</h1>
<button onClick={() => history.push('/') } >Go to home</button>
<FakeText />
</Fragment>
);
在这里,我们history
从收到的 props 中提取对象。它有一些方便的方法,例如goBack
、goForward
等等。但在这里,我们将使用push
方法来转到主页。
现在,让我们处理想要在某个操作后重定向用户的情况。
重定向到另一个页面
React Router 还有一个名为的组件Redirect
,正如你所猜测的,它可以帮助我们将用户重定向到另一个页面
- 在
App.js
import { BrowserRouter as Router, Route, Link, Switch, Redirect } from "react-router-dom";
const About = ({match:{params:{name}}}) => (
// props.match.params.name
<Fragment>
{ name !== 'John Doe' ? <Redirect to="/" /> : null }
<h1>About {name}</h1>
<FakeText />
</Fragment>
);
现在,如果name
作为参数传递的不等于John Doe
,则用户将被重定向到主页。
你可能会问,为什么我不使用 来重定向用户props.history.push('/)
?因为Redirect
组件会替换页面,因此用户无法返回上一页,而使用 push 方法就可以。不过,你可以使用props.history.replace('/)
来模拟这种Redirect
行为。
现在,让我们继续处理用户遇到不存在的路线的情况。
重定向至 404 页面
要将用户重定向到 404 页面,您可以创建一个组件来显示它,但在这里为了简单起见,我将只显示一条消息render
。
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
export default function App() {
const name = 'John Doe'
return (
<Router>
<main>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to={`/about/${name}`}>About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about/:name" component={About} />
<Route path="/contact" component={Contact} />
<Route render={() => <h1>404: page not found</h1>} />
</Switch>
</main>
</Router>
);
}
我们添加的新路线将捕获每个不存在的路径并将用户重定向到 404 页面。
现在,让我们继续下一节学习如何保护我们的路线。
守卫路线
有很多方法可以保护 React 的路由。但在这里,我只会检查用户是否已通过身份验证,并将其重定向到相应的页面。
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
export default function App() {
const name = 'John Doe'
const isAuthenticated = false
return (
<Router>
<main>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to={`/about/${name}`}>About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Switch>
<Route path="/" exact component={Home} />
{
isAuthenticated ?
<>
<Route path="/about/:name" component={About} />
<Route path="/contact" component={Contact} />
</> : <Redirect to="/" />
}
</Switch>
</main>
</Router>
);
}
如您所见,我声明了一个变量来模拟身份验证。然后,检查用户是否已通过身份验证。如果是,则渲染受保护的页面,否则将其重定向到主页。
到目前为止我们已经讨论了很多内容,但仍然有一个有趣的部分:路由器挂钩。
让我们进入最后一部分并介绍 Hooks。

路由器钩子(useHistory、useParams、useLocation)
路由器钩子让事情变得简单多了。现在,访问历史记录、位置或参数都变得简单优雅了。
使用历史
该useHistory
钩子使我们能够访问历史实例,而无需从道具中拉出它。
import { useHistory } from "react-router-dom";
const Contact = () => {
const history = useHistory();
return (
<Fragment>
<h1>Contact</h1>
<button onClick={() => history.push('/') } >Go to home</button>
</Fragment>
)
};
useParams
它帮助我们获取 URL 上传递的参数,而无需使用 props 对象。
import { BrowserRouter as Router, Route, Link, Switch, useParams } from "react-router-dom";
export default function App() {
const name = 'John Doe'
return (
<Router>
<main>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to={`/about/${name}`}>About</Link></li>
</ul>
</nav>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about/:name" component={About} />
</Switch>
</main>
</Router>
);
}
const About = () => {
const { name } = useParams()
return (
// props.match.params.name
<Fragment>
{ name !== 'John Doe' ? <Redirect to="/" /> : null }
<h1>About {name}</h1>
<Route component={Contact} />
</Fragment>
)
};
使用位置
它返回代表当前 URL 的位置对象。
import { useLocation } from "react-router-dom";
const Contact = () => {
const { pathname } = useLocation();
return (
<Fragment>
<h1>Contact</h1>
<p>Current URL: {pathname}</p>
</Fragment>
)
};
最后的想法
React Router 是一个非常棒的库,它帮助我们从单页面应用过渡到多页面应用(最终它仍然是单页面),并且可用性极佳。现在有了路由器钩子,你已经亲眼见证了它是多么的简单和优雅,绝对值得你在下一个项目中考虑。
后续步骤
Joshua Sortino在Unsplash上拍摄的照片
文章来源:https://dev.to/ibrahima92/a-complete-beginner-s-guide-to-react-router-include-router-hooks-kgd