React Router入门指南(包括Router Hooks)

发布于2/23/2020 来自:「前端知否」微信公众号

React是一个用于构建用户界面的JavaScript库。我们还可以借助React Router将其扩展为构建多页应用程序。这是一个第三方库,可在我们的React应用程序中启用路由。

在本教程中,我们将介绍使用React Router入门所需的一切。

初始化项目

为了能够继续学习,您需要通过在终端中运行以下命令来创建一个新的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 = () => (
<>
<h1>Home</h1>
<FakeText />
</>
);

// About Page
const About = () => (
<>
<h1>About</h1>
<FakeText />
</>
);

// Contact Page
const Contact = () => (
<>
<h1>Contact</h1>
<FakeText />
</>
);

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

or

npm install react-router-dom

现在,我们已经成功安装了react router,让我们在下一部分开始使用它。

xxx

设置路由

要在React应用中启用路由,我们首先需要从react-router-dom导入BrowserRouter。

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重命名为Router,我只是想保持可读性。

只有router,还做不了很多事情,让我们在下一节中添加一条路由。

渲染路由

要渲染路由,我们必须从react-router-dom包中导入Route组件。

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>
);
}

然后,将其添加到我们要呈现内容的位置。路线组件具有多个属性。但是在这里,我们只需要路径和渲染。

  • path:这是route的路径。在这里,我们使用 / 定义主页的路径。
  • 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 = () => (
<>
<h1>Home</h1>
<FakeText />
</>
);

现在,我们的路由将不再加载消息,而是加载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 = () => (
<>
<h1>Home</h1>
<FakeText />
</>
);

const About = () => (
<>
<h1>About</h1>
<FakeText />
</>
);

const Contact = () => (
<>
<h1>Contact</h1>
<FakeText />
</>
);

导入链接后,我们必须稍微更新导航栏。

现在,React Router不再使用标签和href,而是使用Link来进行切换,而无需重新加载页面。

然后,我们需要添加两条新路线:“关于”和“联系方式”,以便您也可以在页面或组件之间进行切换。

现在,我们可以通过链接转到应用程序的不同部分。但是,我们的路由器存在问题。即使我们切换到其他页面,Home组件也会一直显示。

原因是React Router将检查定义的路径是否以/开头(如果是),它将呈现组件。

在这里,我们的第一个路径以/开头,因此Home组件每次都会呈现。

但是,我们仍然可以通过将exact属性添加到R​​oute来更改默认行为。

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 = () => (
<>
<h1>Home</h1>
<FakeText />
</>
);

const About = ({ match: { params: { name } } }) => (
// props.match.params.name
<>
<h1>About {name}</h1>
<FakeText />
</>
);

const Contact = () => (
<>
<h1>Contact</h1>
<FakeText />
</>
);

如您在此处看到的,我们首先声明一个新的常量名称,该常量名称将作为参数传递给About页面。并且,我们将名称附加到相应的链接。

这样,我们现在必须通过调整其路径以将名称接收为参数path =“ / about /:name”来更新About路线。

现在,参数将作为About组件中的props接收,我们现在唯一要做的就是对props进行结构分解并获取name属性。顺便说一下,{match:{params:{name}}}与props.match.params.name相同。

到目前为止,我们已经做了很多工作,但是,在某些情况下,我们不想使用链接在页面之间导航。

有时,我们必须等待操作完成才能导航到下一页。

让我们在下一部分中处理这种情况。

以编程方式导航

我们收到的props有一些便捷的方法可用于在页面之间导航。

App.js

const Contact = ({history}) => (
<>
<h1>Contact</h1>
<button onClick={() => history.push('/') } >Go to home</button>
<FakeText />
</>
);

在这里,我们从收到的props中提取history对象。它有一些方便的方法,例如goBack,goForward等。但是在这里,我们将使用push方法来转到主页。

现在,让我们处理重定向用户的情况。

重定向到另一个页面

React Router还有另一个名为Redirect的组件,正如您猜到的,它可以帮助我们将用户重定向到另一个页面。

import { BrowserRouter as Router, Route, Link, Switch, Redirect } from "react-router-dom";

const About = ({ match:{ params: { name } } }) => (
// props.match.params.name
<>
{ name !== 'Foo' ? <Redirect to="/" /> : null }
<h1>About {name}</h1>
<FakeText />
</>
);

现在,如果作为参数传递的名称不等于Foo,则用户将被重定向到主页。

您可能会争论为什么我不使用props.history.push('/')重定向用户?好吧,Redirect组件会替换页面,因此用户无法返回上一页,但是使用push方法,它可以。同样,您还可以使用props.history.replace('/')来模仿重定向行为。

现在,让我们继续处理用户遇到不存在的路由时的情况。

重定向到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 = 'Foo'

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 = 'Foo'
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。

让我们进入最后一节,介绍Hooks。

xxx

路由hooks(useHistory,useParams,useLocation)

路由hooks使事情变得容易得多。现在,以简单而优雅的方式访问历史记录,位置或参数。

useHistory

useHistory钩子使我们可以访问history对象,而无需从props中将其提取。

import { useHistory } from "react-router-dom";

const Contact = () => {
const { history } = useHistory();

return (
<>
<h1>Contact</h1>
<button onClick={ () => history.push('/') } >Go to home</button>
</>
)
};

useParams

它可以帮助我们无需使用props对象就可以在URL上传递参数。

import { BrowserRouter as Router, Route, Link, Switch, useParams } from "react-router-dom";

export default function App() {
const name = 'Foo'

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
<>
{ name !== 'Foo' ? <Redirect to="/" /> : null }
<h1>About {name}</h1>
<Route component={Contact} />
</>
)
};

useLocation

它返回代表当前URL的位置对象。

import { useLocation } from "react-router-dom";

const Contact = () => {
const { pathname } = useLocation();

return (
<>
<h1>Contact</h1>
<p>当前 URL: {pathname}</p>
</>
)
};

最后

React Router是一个了不起的库,它可以帮助我们从一个页面转到一个多页面的应用程序(虽然它仍然是一个页面),并且具有很高的可用性。现在,借助路由hooks,您已经亲眼目睹了它们的简易性和优雅性,绝对是您下一个项目中需要考虑使用的。