React-Router基础(二):BrowserRouter、HashRouter、MemoryRouter 的区别,路由参数

前面我们说过 Router 里面是划分为 BrowserRouter,HashRouter,MemoryRouter 这三种路由的,那么这里我们就来看看它们之间的区别和比较。

首先,第一种 BrowserRouter。

BrowserRouter 它是一个浏览器路由,它依赖的是 HTML5 里面的新特性 history API,它在跳转的时候,就好像地址变了一样,比如我们从首页 /,跳转到 /course,在跳转到 /work:

但其实它没变,因为它根本就没有向服务器请求东西。

因为如果页面真的跳转了,Network 是会有反应的:

可以看到,当我们从 /course 跳转到 /work 的时候,Network 里面根本就没反应,所以它根本就没跳转,它只是直接修改了浏览器的地址栏。

这就是 history API 的作用。它可以在页面不跳转的情况下,直接修改地址栏。

如果你是自己配置 webpack 来搭建项目的话,那么可能会遇到下面这种情况:

假设当你从 / 跳转到了 /course,然后再按下 F5,那么在页面上它会给你展示 Cannot GET /course,并且 Network 里面它也会给你返回 course 这个页面报 404。

因为实际上来说,我们并没有叫做 /course 的这个资源,所以它找不到 /course 这个东西。我们唯一有的就一个,就是根,对应的就是 index.html。其他的东西其实都是假的,所以你不刷新,一切没事,如果你真刷新了,它反而找不着。

所以 BrowserRouter 它是以一个类似于目录,类似于普通 url 的形式,来进行跳转的。

第二种:HashRouter

什么叫 hash,就是你地址#后面的那一段。它叫法很多,也有叫锚点或者其他的。

一旦我们用了 HashRouter,区别是很明显的:

它所有的路径是加在#的后面的。

当然,这个和 BrowserRouter 是一样的,它实际上也是不跳转的:

可以看到,当我们从 /course 跳转到 /work 的时候,它的 Network 里面也是空的。所以效果上是没区别的。

区别就在于,如果我现在去刷新这个页面的话:

可以看到,我现在的地址是 localhost:3000/#/work,但当我去刷新的时候,Network 加载的资源却是 localhost:3000/。

因为现在真实的地址,其实只是这段 localhost:3000/。#后面的这段,根本就不是你地址的一部分。

说的直白点,它根本就不给服务器看,它只是在前台这边来看的。

因为 hash 它其实原本就是在浏览器的一个页面之内来跳转的

所以 BrowserRouter 是以路径的形式来展现的,而 HashRouter 是以 hash 的形式存在的。

它们的区别在于:

1,BrowserRouter 只有 H5 认,所以注定了它只能在高级的浏览器端起作用。

2,hash 不一样,因为它是所有版本的浏览器都认的一个东西,所以它的兼容性更强一些。

那么我们为什么要用 BrowserRouter?

其实是有原因的,当我们用 BrowserRouter 在刷新的时候,它实际上会向服务器去请求数据的。那么这时候,又有什么好处呢?

其实好处还是很明显的:那就是服务器也可以参与到你的这个请求过程当中来。

而 hash,因为它根本就不往服务器那边发,所以服务器是参与不进来的。

所以,BrowserRouter 它如果需要的话,可以跟服务器去配合。而 HashRouter,它无需服务器配置,也不能跟服务器去配置。

这就是它们两个的区别。

还有一种比较奇特的 Router 就是 MemoryRouter:

Memory 就是内存的意思,所以 MemoryRouter 它只存在于内存里面,它不会对地址栏有任何影响。

可以看到,它也能跳转,但是地址是完全不变的,不管你怎么跳路由,它的地址一直都会是 localhost:3000。

因为它是把你这个路由状态,直接保存在它自己的变量里面。它不会体现在浏览器的地址栏上。

那这个时候,它和 HashRouter 其实是有区别的。

比如我现在在作品页,但是一按 F5 刷新,它就直接跳回首页去了。

因为刷新的时候,浏览器是依据于自己当前的那个地址来做的,而当前地址也确实是没有东西的。

而 HashRouter 则不同,因为它已经把地址的一部分做成自己的东西了。

所以它们的特点是:

BrowserRouter 可以跟服务器配合。

HashRouter 无法跟服务器配合。

MemoryRouter 对地址完全不修改。

那么 MemoryRouter 就没用了吗?

因为有时候我们的应用场景里面,真的就是没法修改地址。比如说你用的是 React-Native。

因为 React-Native 是做原生的移动应用。它会把你的 React 编译成 OC、JAVA 之类的东西。所以在这种情况下,如果你用了 BrowserRouter 或者 HashRouter 是会出事的,因为它没有地址栏,你还让它修改地址栏,那就直接出错了。

而 MemoryRouter 它本来就和地址栏没有半毛钱关系,所以在这时候,如果你真的是要用于这种网页之外的情况,其实反而是 MemoryRouter 最好用。

所以这几种 Router 其实用起来,对你来说没有任何的区别,就看你自己怎么去选择它了。

接下来,我们再来看下路由参数。

为了方便,我们先改成 HashRouter。

然后我们在 /course 上设置一个参数, /course/:xxx,这个名字是随便取的。

那么这个时候 :id 就是一个参数。并且这个参数它并不限制 id 一定是数字,字符串等等。

需要注意的是:如果你现在不带 id 去访问 /course,是已经找不到东西的。你会发现它是空的。

因为你定义了 /course 这个路由是要带 id 的,但是你访问的时候又没有带上 id ,所以自然就找不到东西了。

那么我们加上 id:

这个时候,页面上就可以展示课程组件里的内容了:

接下来,还有下一个问题,在这个课程组件里面,我需要知道你传过来的到底是哪个 id:

所以我们需要进到 /course 组件里面,来获取它的参数。

所有的参数都在 props 里面,并且它是只读的,不能改。

其中,props 里面有个 match,我们一起来看看:

可以看到,props 里面的 match 有 4 个属性:

isExact:是不是精确路由。

params:就是你传的参数。

path:就是你现在命中了哪个路径。

url:就是你现在真实的 url。

所以取参数就很简单了,直接从 this.props.match 里面直接拿就可以了:

注意:这时候它会报一个警告,说在 hash 的 history 里面,不能 push 一个相同的 path。

其实 history 就是它里面的一个内置对象,用来保存你这个路由的一个历史信息,可以回退等等一系列的东西。

这是怎么引发的呢?

比如说,我现在是在 /course/22,然后我在点一次 课程2,这个时候就会导致它触发一个还是 22 的路径 push,就会报错了。

然后,我们现在展示的是 Course.js 组件,也就是课程。如果现在需要有一个课程的列表页,怎么做呢?

首先,我们创建一个 CourseList.js,我们希望它可以帮助我们显示一个课程列表。

我们用Link,因为Link最大的好处就是,它可以自动的来处理你各种路由之间的区别和差异。

然后我们再来修改下 Course.js 组件:

同时,在 App.js 里面我们也需要增加节点:

这里的意思就是,如果现在路径就是 /course,没有带 id,那么这时候我认为它是想看 CourseList 课程列表。

只有它带上了 id,我才认为它想要具体的课程。

并且增加一点样式,便于展示:

当我们点击 课程列表 的时候,路由是 /course,下面是没有具体课程的内容。

当我们继续点击 JavaScript 的时候,则展示了具体的课程内容。


这个时候,我们会发现 CourseList 和 Course 两个组件内容都是显示的。

这是因为路由的节点,默认的可以向后匹配。

也就是说,虽然我是在 /course/12 的状态下,但是它的前半节 也符合 /course 的要求,所以 CourseList 和 Course 都会出来。

当然,我们需要的就是这个效果,如果不需要,我们可以加一个精确匹配 exact。

那么现在我们就已经学会了怎么用路由参数。

发布了78 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43921436/article/details/105378841