React Router v4 版本 完全指南

React Router 事實上是React官方的標準路由庫。當你在一個多視圖的React應用中來回切換,你需要一個路由來管理那些URL。React Router 專注於此,同步保持你應用的UI和URL。

這個教程主要給你介紹React Router 的v4版本,以及你使用它可以做的大部分事情。

開場白

React 是一個很流行的庫,用於在客戶端渲染創建的單頁應用(SPAs)。 一個SPA會有很多視圖(也可以稱爲頁面),不像傳統的多頁應用,視圖之間的跳轉不應該導致整個頁面被重新加載。相反,我們希望視圖就在當前頁面裏渲染。那些習慣於多頁應用的最終用戶,期望在一個SPA中應該包含以下特性:

  • 應用中每個視圖都應該有對應的唯一URL用來區分視圖。以便用戶可以在之後通過書籤收藏的URL指向引用資源 – 例如:www.example.com/products
  • 瀏覽器的前進後退按鈕應該正常工作。
  • 動態生成的嵌套視圖更應該有成對應的URL – 例如:example.com/products/shoes/101,101是產品id。

路由跳轉是指在同步保持瀏覽器URL的過程中渲染頁面中的視圖。React Router 讓你聲明式的操作路由跳轉。聲明式路由方法,通過說“路由應該是這樣的”,允許你控制應用中的數據流:

你可以把<Router>組件放在任意你想要路由渲染的地方。由於我們所需要接觸的<Router>,<Link>以及其他React Router的API都只是組件,所以你可以非常方便的在React裏使用路由。

寫在開頭。有一個常見的誤區,大家都認爲React Router是由facebook官方開發的一個路由解決方案。實際上,它是一個因其設計和簡易性而流行的第三方庫。如果你的需求只侷限於路由的跳轉,你可以無需太多麻煩,就可以從頭開始實現一個自定義的路由。但是,瞭解React Router的基礎知識可以讓你更清楚的認識一個路由是怎麼工作的。

概述

React Router Logo

本次教程分爲幾個部分。首先,我們使用npm安裝好React和React Router,然後我們就開始React Router的基礎部分。你將會看到React Router不同的代碼示例的效果。本次教程涉及的例子包含:

  1. 基本路由跳轉
  2. 嵌套路由
  3. 帶路徑參數的嵌套路由
  4. 保護式路由

主要圍繞構建這些路由所涉及的概念進行討論。這個項目的全部代碼在這個Github倉庫可以看到。當你進入一個單獨的demo目錄,執行npm install來安裝依賴。要在本地服務器上運行這個應用,執行npm start,然後在瀏覽器打開http://localhost:3000/可以看到運行的demo。

讓我們開始吧!

安裝 React Router

假設你已經有一個React開發環境並已經運行了。如果沒有,可以跳轉到React和JSX入門。或者,你可以使用Create React App來生成創建一個基本的React項目所需要的文件。這是Create React App生成的默認目錄結構:

React Router庫包含三個包: react-routerreact-router-dom, 和 react-router-nativereact-router是路由的核心包,而其他兩個是基於特定環境的。如果你在開發一個網站,你應該使用react-router-dom,如果你在移動應用的開發環境使用React Native,你應該使用react-router-native

使用npm安裝react-router-dom

React Router 基礎

下面是路由的例子:

Router

像上面的例子,你需要一個組件和一些組件來創建一個基本的路由。由於我們創建的是一個基於瀏覽器的應用,我們可以從React Router API中使用這兩種類型的路由:

  1. <BrowserRouter>
  2. <HashRouter>

它們之間主要的區別,可以在它們所創建的URL明顯看出:

<BrowserRouter>在兩者中更爲常用,原因是它使用了HTML5的history API來記錄你的路由歷史。而<HashRouter>則使用URL(window.location.hash)的hash部分來記錄。如果你想兼容老式瀏覽器,你應該使用<HashRouter>

使用<BrowserRouter>組件包裹App組件。

index.js

注意:Router組件只能有一個子元素。子元素可以是HTML – 例如div – 也可以是一個react組件。

要讓React Router工作,你需要從react-router-dom庫引入相關的API。這裏,我在index.js引入了BrowserRouter,也從App.js引入了App組件。App.js,如你所猜想的,是React組件的入口。

上述代碼給我們整個App組件創建了一個history實例。接下來正式介紹下history。

history

history是一個讓你輕鬆管理所有Javascript運行的會話記錄的Javascript庫。history提供了簡潔的API,讓你可以管理history堆棧,跳轉,確認跳轉,以及保持會話之間的狀態。 – 來自React 培訓文檔

每個router組件創建了一個history對象,用來記錄當前路徑(history.location),上一步路徑也存儲在堆棧中。當前路徑改變時,視圖會重新渲染,給你一種跳轉的感覺。當前路徑又是如何改變的呢?history對象有history.push()history.replace()這些方法來實現。當你點擊組件會觸發history.push(),使用則會調用history.replace()。其他方法 – 例如history.goBack()history.goForward() – 用來根據頁面的後退和前進來跳轉history堆棧。

接下來,我們談談Links和Routes

Links and Routes

是React Router裏最重要的組件。若當前路徑匹配route的路徑,它會渲染對應的UI。理想來說,應該有一個叫path的prop,當路徑名跟當前路徑匹配纔會渲染。

另一方面,用來跳轉頁面。可以類比HTML的錨元素。然而,使用錨鏈接會導致瀏覽器的刷新,這不是我們想要的。所以,我們可以使用來跳轉至具體的URL,並且視圖重新渲染不會導致瀏覽器刷新。

我們已經介紹了創建一個基本的路由需要的所有東西。讓我們試一個吧。

Demo 1: 基礎路由

src/App.js


我們在App.js裏定義了 Home,Category,和Products組件。儘管目前看起來沒問題,當組件變得越來越臃腫,最好將每個組件分成單獨的文件。根據經驗,如果組件代碼超過了10行,我通常會給它創建一個新的文件。從第二個demo開始,我會將App.js裏面越來越多的組件分成單獨的文件。

在App組件中,我們寫了路由跳轉的邏輯。 的路徑與當前路徑匹配,對應組件就會被渲染。對應渲染的組件傳給了第二個prop–component

在這裏,/同時匹配//category。因此,所有路由都匹配並被渲染。我們該如何避免呢?應該給 path='/'的路由傳遞exact= {true}props:

若只想要路由在路徑完全相同時渲染,你就可以使用exactprops。

嵌套路由

創建嵌套路由之前,我們需要更深入的理解如何運行。開始吧。

<Route>有三個可以用來定義要渲染內容的props:

  • component.在上面我們已經看到了。當URL匹配時,router會將傳遞的組件使用React.createElement來生成一個React元素。
  • render. 適合行內渲染。在當前路徑匹配路由路徑時,renderprop期望一個函數返回一個元素。
  • children.childrenprop跟render很類似,也期望一個函數返回一個React元素。然而,不管路徑是否匹配,children都會渲染。

Path and match

path用來標識路由匹配的URL部分。React Router使用了Path-to-RegExp庫將路徑字符串轉爲正則表達式。然後正則表達式會匹配當前路徑。

當路由路徑和當前路徑成功匹配,會生成一個對象,我們叫它match。match對象有更多關於URL和path的信息。這些信息可以通過它的屬性獲取,如下所示:

  • match.url.返回URL匹配部分的字符串。對於創建嵌套的很有用。
  • match.path.返回路由路徑字符串 – 就是。將用來創建嵌套的
  • match.isExact.返回布爾值,如果準確(沒有任何多餘字符)匹配則返回true。
  • match.params.返回一個對象包含Path-to-RegExp包從URL解析的鍵值對。

現在我們完全瞭解了,開始創建一個嵌套路由吧。

Switch組件

在我們開始示例代碼籤,我想給你介紹下組件。當一起使用多個時,所有匹配的routes都會被渲染。根據demo1的代碼,我添加一個新的route來驗證爲什麼很有用。

當URL爲/products,所有匹配/products路徑的route都會被渲染。所以,那個path爲:id的<Route>會跟着Products組件一塊渲染。設計就是如此。但是,若這不是你想要的結果,你應該給你的routes添加<Switch>組件。有<Switch>組件的話,只有第一個匹配路徑的子<Route>會渲染。

Demo 2: 嵌套路由

之前,我們給//category and /products創建了路由。但如果我們想要/category/shoes這種形式的URL呢?

src/App.js


不像React Router之前的版本,在版本4中,嵌套的最好放在父元素裏面。所以,Category組件就是這裏的父組件,我們將在父組件中定義category/:name路由。

src/Category.jsx


首先,我們給嵌套路由定義了一些Link。之前提到過,match.url用來構建嵌套鏈接,match.path用來構建嵌套路由。如果你對match有不理解的概念,console.log(match)會提供一些有用的信息來幫助你瞭解它。

這是我們首次嘗試動態路由。不同於硬編碼路由,我們給pathname使用了變量。:name是路徑參數,獲取category/之後到下一條斜槓之間的所有內容。所以,類似products/running-shoes的路徑名會生成如下的一個params對象:

參數可以通過match.paramsprops.match.params來獲取,取決於傳遞哪種props。另外有趣的是我們使用了renderprop。render props非常適合行內函數,這樣不需要單獨拆分組件。

Demo 3: 帶Path參數的嵌套路由

我們讓事情變得再複雜一些,可以嗎?一個真實的路由應該是根據數據,然後動態展示。假設我們獲取了從服務端API返回的product數據,如下所示。

src/Products.jsx

我們需要根據下面這些路徑創建路由:

  • /products. 這個路徑應該展示產品列表。
  • /products/:productId.如果產品有:productId,這個頁面應該展示該產品的數據,如果沒有,就該展示一個錯誤信息。

src/Products.jsx


首先,我們通過productsData.id創建一列,並把它存儲在linkList。路由從路徑字符串根據匹配的對應產品id獲取參數。

你可能期望使用component = { Product }來替代行內render函數。問題是,我們不僅需要productsData,並順帶把剩餘prop也傳給Product組件。儘管你還有其他方法,不過我覺的這是最簡單的方法了。{...props}使用ES6的擴展運算符 將所有prop傳給組件。

這是Product組件的代碼。

src/Product.jsx

find方法用來查找數組中對象的id屬性等於match.params.productId。如果product存在,productData就會展示,如果不存在,“Product不存在”的信息就會被渲染。

保護式路由

最後一個demo,我們將圍繞保護式路由的技術進行討論。那麼,如果有人想進入/admin頁面,他們會被要求先登錄。然而,在我們保護路由之前還需要考慮一些事情。

重定向

類似服務端重定向,會將history堆棧的當前路徑替換爲新路徑。新路徑通過toprop傳遞。這是如何使用

如果有人已經註銷了賬戶,想進入/admin頁面,他們會被重定向到/login頁面。當前路徑的信息是通過state傳遞的,若用戶信息驗證成功,用戶會被重定向回初始路徑。在子組件中,你可以通過this.props.location.state獲取state的信息。

自定義路由

自定義路由最適合描述組件裏嵌套的路由。如果我們需要確定一個路由是否應該渲染,最好的方法是寫個自定義組件。下面是通過其他路由來定義自定義路由。

src/App.js

若用戶已登錄,fakeAuth.isAuthenticated返回true,反之亦然。

這是PrivateRoute的定義。

src/App.js

如果用戶已登錄,路由將渲染Admin組件。否則,用戶將重定義到 /login登錄頁面。這樣做的好處是,定義更明確,而且PrivateRoute可以複用。

最後,下面是Login組件的代碼:

src/Login.jsx


下面這行是對象的解構賦值的示例,es6的特性之一。

讓我們把所有片段拼湊到一塊,好嗎?這是我們使用React Router創建的應用最終效果:

Demo 4: 保護式路由

點擊此查看在線demo

總結

如你在本文中所看到的,React Router是一個幫助React構建更完美,更聲明式的路由庫。不像React Router之前的版本,在v4中,一切就“只是組件”。而且,新的設計模式也更完美的使用React的構建方式來實現。

在本次教程中,我們學到了:

  • 如何配置和安裝React Router
  • 基礎版路由,和一些基礎組件,例如
  • 如何構建一個有導航功能的極簡路由和嵌套路由
  • 如何根據路徑參數構建動態路由

最後,我們還學習了一些高級路由技巧,用來創建保護式路由的最終demo。

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