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。

那麼現在我們就已經學會了怎麼用路由參數。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章