路由是保持浏览器URL与页面上呈现的内容同步的过程。React路由器让你处理路由以声明的方式.声明式路由方法允许你控制应用程序中的数据流,通过说“路由应该是这样的”:

<路线路径“/”><关于/></路线>

你可以把你的<路径>组件在任何你想渲染你的路由的地方。自<路径><链接>我们将要处理的所有其他React路由器api都只是组件,你可以轻松地在React中启动和运行路由。

不是来自Facebook

有一种常见的误解,认为React Router是Facebook开发的官方路由解决方案。实际上,它是一个以其设计和简单性而广受欢迎的第三方库。

概述

本教程分为不同的部分。首先,我们将使用npm设置React和React路由器。然后我们将直接进入一些React路由器基础知识。你会发现React路由器的不同代码演示。本教程中涉及的示例包括:

  • 基本导航路由<李class="">嵌套的路由<李class="">带有路径参数的嵌套路由<李class="">保护路由

所有与建设这些路线有关的概念都将在途中进行讨论。

项目的全部代码可在这个GitHub回购

让我们开始吧!

设置React路由器

要学习本教程,您需要在您的PC上安装Node的最新版本。如果不是这样,那么转到Node主页并为您的系统下载正确的二进制文件.或者,您可以考虑使用版本管理器来安装Node。我们有一个这里是使用版本管理器的教程

Node与npm捆绑在一起,npm是JavaScript的包管理器,我们将用它安装一些我们将使用的库。你可以点击这里了解更多关于使用NPM的知识

您可以通过从命令行发出以下命令来检查两者是否正确安装:

节点- v>12.19.0npm- v>6.14.8

完成这些后,让我们开始创建一个新的React项目创建React应用工具。您可以全局安装它,也可以使用它npx,像这样:

create-react-app react-router-demo

完成后,切换到新创建的目录:

cdreact-router-demo

React Router库包含三个包:react-routerreact-router-dom,react-router-native.路由器的核心包是react-router,而其他两个则是特定于环境的。你应该使用react-router-dom如果你要建一个网站react-router-native如果你在一个使用React Native的移动应用程序开发环境中。

使用npm进行安装react-router-dom

npm安装react-router-dom

然后启动开发服务器:

npm运行开始

恭喜你!你现在有一个工作的React应用程序,安装了React路由器。您可以查看运行的应用程序http://localhost:3000/

React路由器基础知识

现在让我们熟悉一个基本的React路由器设置。为此,我们将创建一个具有三个独立视图的应用程序:Home、Category和Products。

路由器组件

我们要做的第一件事是把我们的<应用>组件<路由器>组件(由React Router提供)。由于我们正在构建一个基于浏览器的应用程序,我们可以使用React router API中的两种类型的路由器:

它们之间的主要区别是它们创建的url:

/ / < BrowserRouter >http//例子com/关于/ / < HashRouter >http//例子com//关于

< BrowserRouter >这两者中比较受欢迎是因为它使用了theHTML5历史API以保持UI与URL同步,而< HashRouter >使用URL的哈希部分(window.location.hash).如果您需要支持不支持History API的旧浏览器,则应该使用< HashRouter >.否则< BrowserRouter >对于大多数用例来说是更好的选择。你可以点击这里阅读更多不同之处

让我们导入BrowserRouter组件,并将其围绕应用程序组件:

/ / src / index.js进口反应“反应”进口ReactDOM“react-dom”进口应用程序”。/应用程序”进口BrowserRouter“react-router-dom”ReactDOM渲染<BrowserRouter><应用程序/></BrowserRouter>文档getElementById“根”

上面的代码创建一个历史整个实例<应用>组件。让我们看看这意味着什么。

《一点点历史

历史库可以让你轻松地管理任何JavaScript运行的会话历史。一个历史对象抽象了各种环境中的差异,并提供了一个最小的API,让您可以管理历史堆栈、导航和在会话之间保持状态。- - - - - -React培训文档

每一个<路由器>组件创建历史对象,该对象跟踪当前位置(history.location)和堆栈中先前的位置。当当前位置发生变化时,视图将被重新渲染,您将获得一种导航感。当前位置如何变化?历史对象具有history.push而且history.replace来解决这个问题。的history.push方法时调用<链接>组件,history.replace调用< >重定向.其他方法——例如history.goBack而且history.goForward-用于通过向后或向前浏览历史堆栈。

继续,我们有链接和路线。

链接而且路线组件

<路径>组件是React路由器中最重要的组件。如果当前位置与路由路径匹配,它会呈现一些UI。理想情况下,一个<路径>组件应该有一个名为路径,如果路径名与当前位置匹配,则会呈现该路径。

<链接>另一方面,组件用于在页面之间导航。它可以与HTML锚元素相比较。然而,使用锚链接会导致整个页面刷新,这是我们不希望看到的。所以我们可以用<链接>导航到一个特定的URL,并重新渲染视图而不刷新。

现在我们已经涵盖了使我们的应用程序工作所需的所有内容。更新src / App.js如下:

进口反应“反应”进口链接路线开关“react-router-dom”常量首页= ><div><h2>首页</h2></div>常量类别= ><div><h2>类别</h2></div>常量产品= ><div><h2>产品</h2></div>出口默认的函数应用程序返回<div><导航名称“navbar navbar-light”><ul类名“nav navbar-nav”><><链接“/”>首页</链接></><><链接“/类别”>类别</链接></><><链接“/产品”>产品</链接></></ul></导航>/*如果路径道具与当前URL */匹配,则呈现路由组件<路线路径“/”><首页/></路线><路线路径“/类别”><类别/></路线><路线路径“/产品”><产品/></路线></div>

这里,我们声明了for的组件首页类别而且产品内部App.js.虽然现在这样做还可以,但是当一个组件开始变大时,最好为每个组件创建一个单独的文件。根据经验,如果组件占用的代码超过10行,我通常会为它创建一个新文件。从第二个演示开始,我将为组件创建一个单独的文件,这些组件由于太大而无法放入App.js文件。

应用程序组件,我们已经编写了路由的逻辑。的<路径>的路径与当前位置匹配,并呈现一个组件。以前,应该呈现的组件是作为第二个道具传入的。然而,React Router的最新版本引入了一种新的路由呈现模式,即要呈现的组件是<路径>

在这里/匹配两个/而且/类别.因此,两条路由都被匹配和呈现。我们如何避免这种情况?你应该通过确切的道具到<路径>路径= ' / '

<路线具体的路径“/”><首页/></路线>

如果您希望仅在路径完全相同时才呈现路由,则应该使用确切的道具

嵌套的路由

要创建嵌套路由,我们需要更好地理解如何创建<路径>的工作原理。我们现在来看一下。

正如你可以读到的React路由器文档的推荐方法<路径>就是使用孩子们元素,如上所示。但是,还有一些其他方法可以使用<路径>.这些主要用于支持在钩子引入之前用路由器的早期版本构建的应用程序:

  • 组件:当URL匹配时,路由器使用React.createElement<李class="">渲染:方便内联渲染。的渲染Prop期望一个函数在位置与路由路径匹配时返回一个元素。<李class="">孩子们:这与渲染,因为它期望一个返回React组件的函数。然而,孩子们无论路径是否与位置匹配,都将呈现。

路径和匹配

路径prop用于识别路由器应该匹配的URL部分。它使用Path-to-RegExp图书馆将路径字符串转换为正则表达式。然后它将与当前位置进行匹配。

如果路由器的路径和位置成功匹配,则会创建一个名为a的对象匹配对象.的匹配对象包含有关URL和路径的更多信息。该信息可通过下面列出的属性访问:

  • match.url:返回URL匹配部分的字符串。这对于构建嵌套尤其有用<链接>组件。<李class="">match.path:返回路由路径字符串的字符串,即,<路由路径= " " >.我们会用这个来构建嵌套<路径>组件。<李class="">match.isExact:一个布尔值,如果匹配是精确的(没有任何尾随字符)则返回true。<李class="">match.params:包含由Path-to-RegExp包解析的URL中的键/值对的对象。

道具的隐式传递

注意,当使用组件道具以呈现路线,则匹配位置而且历史路由道具隐式地传递给组件。当使用较新的路由呈现模式时,情况并非如此。

例如,以这个组件为例:

常量首页道具= >控制台日志道具返回<div><h2>首页</h2></div>

现在像这样渲染路由:

<路线具体的路径“/”组件首页/>

这将记录以下内容:

历史...位置...匹配...

但是现在要像这样渲染路由:

<路线具体的路径“/”><首页/></路线>

这将记录以下内容:

这可能一开始看起来很不利,但不用担心!React v5.1引入了几个钩子来帮助你在需要的地方访问你需要的东西。这些钩子为我们提供了管理路由器状态的新方法,并在一定程度上整理了我们的组件。

我将在本教程中使用这些钩子中的一些,但如果您想更深入地了解,请查看React路由器v5.1发布公告.请注意,钩子是在React的16.8版本中引入的,所以你至少需要在那个版本上才能使用它们。

开关组件

在开始演示代码之前,我想向您介绍开关组件.当多个<路径>S被一起使用,所有匹配的路由都被包含呈现。考虑演示1中的代码。我添加了一条新路线来说明原因<转>是有用的:

<路线具体的路径“/”><首页/></路线><路线路径“/类别”><类别/></路线><路线路径“/产品”><产品/></路线><路线路径/: id”><p>文本将被渲染其他路线' / '</p></路线>

如果URL为/产品,所有与该位置匹配的路线/产品被渲染。所以,<路径>与路径/: id属性一起呈现<产品>组件。这是有意为之。但是,如果这不是您所期望的行为,则应该添加<转>组件的路由。与<转>,只有第一个孩子<路径>匹配的位置被渲染:

<开关><路线具体的路径“/”><首页/></路线><路线路径“/类别”><类别/></路线><路线路径“/产品”><产品/></路线><路线路径/: id”><p>文本将被渲染除上述定义的路由之外的任何路由</p></路线></开关>

: id的一部分路径用于动态路由。它将匹配斜杠之后的任何内容,并使该值在组件中可用。在下一节中,我们将看到一个实例。

既然我们都知道了<路径>而且<转>组件,让我们在演示中添加嵌套路由。

动态嵌套路由

之前,我们为//类别而且/产品.但是如果我们想要一个形式为/类别/鞋?

让我们从更新开始src / App.js如下:

进口反应“反应”进口链接路线开关“react-router-dom”进口类别”。/类别”常量首页= ><div><h2>首页</h2></div>常量产品= ><div><h2>产品</h2></div>出口默认的函数应用程序返回<div><导航名称“navbar navbar-light”><ul类名“nav navbar-nav”><><链接“/”>首页</链接></><><链接“/类别”>类别</链接></><><链接“/产品”>产品</链接></></ul></导航><开关><路线路径“/”><首页/></路线><路线路径“/类别”><类别/></路线><路线路径“/产品”><产品/></路线></开关></div>

你会注意到我们移动了类别变成它自己的组件。这是我们的嵌套路由应该去的地方。

让我们创建Category.js现在:

/ / src / Category.js进口反应“反应”进口链接路线useParamsuseRouteMatch“react-router-dom”常量= >常量的名字useParams返回<div><h3>的名字</h3></div>常量类别= >常量url路径useRouteMatch返回<div><ul><><链接$ {url/鞋>鞋子</链接></><><链接$ {url/靴子>靴子</链接></><><链接$ {url/鞋类>鞋子</链接></></ul><路线路径$ {路径/:名称></></路线></div>出口默认的类别

这里,我们用useRouteMatch钩获得访问权限匹配对象。如前所述,match.url将用于构建嵌套链接和match.path对于嵌套路由。如果你在理解匹配的概念上有困难,console.log (useRouteMatch ())提供一些有用的信息,可能有助于澄清它。

<路线路径$ {路径/:名称></></路线>

这是我们对动态路由的第一次正确尝试。中使用了一个变量,而不是硬编码路由路径道具。:名称是一个路径参数和捕获一切之后类别/直到遇到另一个正斜杠。路径名是产品/跑鞋将创建一个参数个数对象如下:

的名字“跑步鞋”

方法中访问此值<项目>组件,我们使用useParams钩,它返回一个URL参数的键/值对对象。

在浏览器中试试这个。Category部分现在应该有三个子部分,每个子部分都有自己的路由。

带有路径参数的嵌套路由

让我们把事情复杂化一点,好吗?现实世界中的路由器必须处理数据并动态显示。让我们假设我们有一些由API返回的产品数据,格式如下:

常量productDataid1的名字“NIKE Liteforce蓝色运动鞋”描述"我与你同在,神圣的至尊。Proin molestie。”状态“可用”id2的名字“时尚人字拖和拖鞋”描述"美好的生活,美好的生活,美好的生活"状态“缺货”id3.的名字“ADIDAS Adispree跑鞋”描述“Maecenas condimentum porttitor auctor。Maecenas viverra fringilla felis, eu pretium。”状态“可用”id4的名字“ADIDAS中号运动鞋”描述"这是威尼斯的伤口,这是发酵的伤口"状态“缺货”

让我们还假设我们需要为以下路径创建路由:

  • /产品:这应该显示一个产品列表。<李class="">/ /产品:productId:如果产品带有: productId如果存在,则应该显示产品数据,如果不存在,则应该显示错误消息。

创建一个新文件src / Products.js并添加以下内容(请确保从上面复制产品数据):

进口反应“反应”进口链接路线useRouteMatch“react-router-dom”进口产品”。/产品”常量产品匹配= >常量productData...常量urluseRouteMatch/*为每个产品创建一个' 
  • '项的数组*/常量linkListproductData地图产品= >返回<李的关键产品id><链接$ {url/$ {产品id>产品的名字</链接></>返回<div><div><div><h3>产品</h3><ul>linkList</ul></div></div><路线路径$ {url/: productId><产品数据productData/></路线><路线具体的路径url><p>选择产品</p></路线></div>出口默认的产品
  • 首先,我们使用useRouteMatch钩子从匹配对象。然后我们建立一个列表<链接>组件使用id属性,我们将其存储在linkList变量。

    方法中的变量路径prop,它与产品ID对应。当它匹配时,我们渲染<产品>组件(我们将在一分钟内定义),将我们的产品数据传递给它:

    <路线路径$ {url/: productId><产品数据productData/></路线>

    第二条路线有一个确切的prop,所以只在URL为时才会渲染/产品什么都没有被选中。

    现在,这是<产品>组件。您需要在src / Product.js

    进口反应“反应”进口useParams“react-router-dom”常量产品数据= >常量productIduseParams常量产品数据找到p= >pid= = =数量productIdproductData如果产品productData<div><h3>产品的名字</h3><p>产品描述</p><人力资源/><h4>产品状态</h4></div>其他的productData<h2>对不起产品不存在</h2>返回<div><div>productData</div></div>出口默认的产品

    找到方法用于在数组中搜索ID属性为的对象match.params.productId.如果产品存在,则productData会显示出来。如果不存在,则呈现“产品不存在”消息。

    最后,更新你的<应用>组成部分如下:

    进口反应“反应”进口链接路线开关“react-router-dom”进口类别”。/类别”进口产品”。/产品”常量首页= ><div><h2>首页</h2></div>出口默认的函数应用程序返回<div><导航名称“navbar navbar-light”><ul类名“nav navbar-nav”><><链接“/”>首页</链接></><><链接“/类别”>类别</链接></><><链接“/产品”>产品</链接></></ul></导航><开关><路线具体的路径“/”><首页/></路线><路线路径“/类别”><类别/></路线><路线路径“/产品”><产品/></路线></开关></div>

    现在,当您在浏览器中访问应用程序并选择“Products”时,您将看到呈现的子菜单,该菜单依次显示产品数据。

    试玩一下demo。向自己保证一切正常,并理解代码中发生的事情。

    保护线路

    许多现代web应用程序的一个共同要求是确保只有登录用户才能访问网站的某些部分。在下一节中,我们将研究如何实现受保护路由,以便如果有人试图访问/管理,他们将被要求登录。

    然而,React路由器有几个方面我们需要先介绍一下。

    重定向组件

    与服务器端重定向一样,React路由器的重定向组件将用新位置替换历史堆栈中的当前位置。方法指定新位置道具。下面是我们使用的方法< >重定向

    <重定向路径名/登录的状态位置

    如果有人试图访问/管理路径,它们将被重定向到/登录路线。控件传递有关当前位置的信息状态道具,这样如果身份验证成功,用户就可以重定向到他们最初试图访问的页面。

    定制的路线

    自定义路由是描述嵌套在组件中的路由的一种奇特方式。如果我们需要决定是否应该呈现一个路由,那么编写一个自定义路由是可行的方法。

    创建一个新文件PrivateRoute.jssrc目录并添加以下内容:

    进口反应“反应”进口重定向路线useLocation“react-router-dom”进口fakeAuth”。/登录的常量PrivateRoute组件组件...休息= >常量位置useLocation返回<路线...休息>fakeAuthisAuthenticated= = =真正的?<组件/><重定向路径名“/登录”状态位置/></路线>出口默认的PrivateRoute

    如您所见,在函数定义中,我们将接收到的props解构为a组件道具和休息道具。的组件Prop将包含我们的任何组件< PrivateRoute >保护(在我们的例子中,管理).的休息Prop将包含我们已经传递的任何其他道具。

    然后返回<路径>组件,它呈现受保护的组件或将我们重定向到我们的/登录路由,取决于用户是否登录。这由a决定fakeAuth.isAuthenticated属性导入的登录> <组件。

    这种方法的优点是,它显然更具有声明性< PrivateRoute >是可重用的。

    重要保安须知

    在现实应用中,您需要在服务器上验证对受保护资源的任何请求.这是因为在客户端中运行的任何东西都可能被逆向工程和篡改。例如,在上面的代码中,你可以打开React的开发工具并更改的值isAuthenticated,从而获得进入保护区的权利。

    React应用程序中的身份验证值得专门的教程,但实现它的一种方法是使用JSON Web令牌.例如,您可以在服务器上设置一个端点,该端点接受用户名和密码组合。当它收到这些(通过Ajax)时,它检查凭证是否有效。如果是,它会响应一个JWT, React应用程序将其保存(例如在sessionStorage),如果不是,则发送一个401年未经授权向客户端返回响应。

    假设成功登录,客户端随后将JWT作为头部连同对受保护资源的任何请求一起发送。然后,服务器在发送响应之前对其进行验证。

    存储密码时,服务器不会以明文形式存储它们.相反,它会加密它们——例如,使用bcryptjs

    实现受保护路由

    现在让我们实现受保护的路由。改变src / App.js像这样:

    进口反应“反应”进口链接路线开关“react-router-dom”进口类别”。/类别”进口产品”。/产品”进口登录”。/登录的进口PrivateRoute”。/ PrivateRoute”常量首页= ><div><h2>首页</h2></div>常量管理= ><div><h2>欢迎管理</h2></div>出口默认的函数应用程序返回<div><导航名称“navbar navbar-light”><ul类名“nav navbar-nav”><><链接“/”>首页</链接></><><链接“/类别”>类别</链接></><><链接“/产品”>产品</链接></><><链接“/管理”>管理区域</链接></></ul></导航><开关><路线具体的路径“/”><首页/></路线><路线路径“/类别”><类别/></路线><路线路径“/产品”><产品/></路线><路线路径“/登录”><登录/></路线><PrivateRoute路径“/管理”组件管理/></开关></div>

    如你所见,我们添加了一个<管理>组件添加到文件顶部,并包括我们的< PrivateRoute ><转>组件。如前所述,此自定义路由呈现<管理>组件,如果用户已登录。否则,用户被重定向到/登录

    最后,这是Login组件的代码:

    进口反应useState“反应”进口重定向useLocation“react-router-dom”出口默认的函数登录常量状态useLocation常量状态||路径名“/”常量redirectToReferrersetRedirectToReferreruseState常量登录= >fakeAuth进行身份验证= >setRedirectToReferrer真正的如果redirectToReferrer返回<重定向/>返回<div><p>必须记录浏览网页路径名</p><按钮onClick登录>日志</按钮></div>/*一个伪认证函数*/出口常量fakeAuthisAuthenticated进行身份验证cbisAuthenticated真正的setTimeoutcbOne hundred.

    到目前为止,希望没有太棘手的事情发生。我们使用useLocation钩访问路由器的位置道具,我们从中获取状态财产。然后我们使用对象解构来获取用户在被要求登录之前试图访问的URL的值。如果这个不存在,我们将它设置为{pathname: "/"}

    然后我们使用React的useState钩子来初始化redirectToReferrer财产.根据这个属性的值,用户或者被重定向到他们要去的地方(也就是说,用户已经登录),或者显示一个按钮让用户登录。

    按钮被单击后,fakeAuth.authenticate方法,该方法设置fakeAuth.isAuthenticated真正的和(在回调函数中)更新的值redirectToReferrer真正的.这将导致组件重新呈现,用户被重定向。

    演示工作

    让我们把这些拼图拼在一起,好吗?下面是我们使用React路由器构建的应用程序的最终演示。

    总结

    正如你在本指南中所看到的,React Router是一个功能强大的库,它可以补充React来构建更好的声明性路由。与React Router的早期版本不同,在v5中,一切都“只是组件”。此外,新的设计模式完全符合React的做事方式。

    在本教程中,我们学习了:

    • 如何设置和安装React路由器<李class="">路由的基础知识和一些基本组件,如<路由器><路径>而且<链接>
    • 如何创建导航和嵌套路由的最小路由器<李class="">如何建立具有路径参数的动态路由<李class="">如何使用React路由器的钩子和它更新的路由渲染模式

    最后,我们学习了一些高级路由技术,用于创建受保护路由的最终演示。

    社区问题

    <按钮class="border-2 rounded-sm transition-colors cursor-pointer disabled:cursor-not-allowed disabled:pointer-events-none border-none text-primary-700 hover:text-primary-500 dark:text-primary-300 dark:hover:text-primary-200 disabled:text-primary-100 px-2 py-1 text-xs font-bold flex items-center">关闭
    Baidu