React Router 使用

前言

做爲 React 全家桶的一員,若是咱們想要開發一個 React 應用,那麼 react-router 基本上是咱們繞不過去的基礎。基於此,對它的瞭解和使用也是必不可少的一步html

本文將重點介紹實際應用中經常使用的一些 API 以及實踐過程當中遇到的一些問題,目標很簡單:會用前端

基於 react-router v5.0.1WEB 應用程序

安裝

國際慣例,首先咱們須要安裝vue

npm install --save react-router-dom

從這一步開始,已經有同窗有疑問了:咱們明明在說 react-router 怎麼要下載安裝 react-router-domreact

React Router 如今已經被劃分紅了三個包:react-routerreact-router-domreact-router-nativegit

react-routerReact Router 應用提供了核心的路由組件和函數,另外兩個包提供了特定環境的組件(瀏覽器和 react-native 對應的平臺),不過他們也是將 react-router 導出的模塊再次導出

由於咱們須要開發一個 web 應用,因此直接安裝 react-router-dom 就能夠了github

初體驗

首先,讓咱們經過一個小小的示例來感知一下 react-routerweb

import React from 'react'
import ReactDom from 'react-dom'
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'

const Index = () => <div>Index頁面</div>

const About = () => <div>About頁面</div>

const App = () => {
    return (
        <BrowserRouter>
            <div>
                <div>
                    <ul>
                        <li><Link to='/'>Index</Link></li>
                        <li><Link to='/about'>About</Link></li>
                    </ul>
                </div>
                <div>
                    <Switch>
                        <Route path='/' exact component={Index}></Route>
                        <Route path='/about' exact component={About}></Route>
                    </Switch>
                </div>
            </div>
        </BrowserRouter>
    )
}

ReactDom.render(<App />, document.getElementById('app'))

經過上面的代碼咱們已經實現了路由的基本功能,匹配不一樣的路徑,渲染不一樣的組件。下面,咱們就上面的示例,認識一些 react-router 中高頻率出現的概念vue-router

經常使用組件

Router 組件

React Router 應用程序的核心,每一個 router 都會建立一個 history 對象,用來保持對當前位置的追蹤npm

web 項目中,react-router-dom 提供了 BrowserRouterHashRouter 路由。這兩個路由都會爲你建立一個專門的 history 對象。至於使用場景,通常狀況下若是咱們使用的是一個非靜態的站點、要處理不一樣的 url 就使用 BrowserRouter,相反若是隻處理靜態的 url,則使用 HashRouter編程

Route 組件

Route 組件的主要職責:當連接符合匹配規則時,渲染組件

路由匹配是經過比較 Routepath 屬性和當前地址的 pathname 來實現的。當一個 Route 匹配成功時,它將渲染其內容,當它不匹配時就會渲染 null。沒有路徑的 Route 將始終被匹配

Route 組件經常使用屬性:

  • path: 字符串類型,用來匹配 ulr
  • exact: boolean 類型,若是爲 true,則只有在路徑徹底匹配 location.pathname 時才匹配
  • component: 只有當位置匹配時纔會渲染的 React 組件

注意點:

Route 組件屬性都不是必須的,若是缺乏 path 屬性,那麼將會匹配到任意 url
<Route path='/' exact component={Index} />
<Route component={About} />
使用 render 或者 children 屬性能夠替代 component 屬性,因爲 renderchildren 都是函數的形式,因此能夠在它們當中作一些比較複雜的邏輯

render 函數也是在匹配 url 的時候渲染,而 children 函數 任什麼時候候 都渲染,當路由匹配的時候 match 是一個對象,不然爲 null

當三者一塊兒使用的時候,優先級爲 children > component > render

<!-- 使用 render 屬性 -->
<Route path='/about' render={() => <div>這個是render渲染的about頁面</div>} />

<Route path='/about' render={(props) => <About {...props} />} />

<!-- 使用 children 屬性 -->
<Route path='/about' children={() => <div>這是一個children渲染的about頁面</div>}

<Route path='/about' children={({match}) => match ? <div>1</div> : <div>2</div> }

Switch 組件

渲染與該地址匹配的第一個子節點 Route 或者 Redirect

這個組件最重要的做用是能夠將 Route 組件分組

<Switch>
    <Route path='/user' render={()=><div>user頁面</div>} />
    <Route path='/:id' render={()=><div>子成員</div>} />
    <Route render={()=><div>about頁面</div>} />
</Switch>

在上面這個示例中,在沒有 Switch 組件包裹的狀況下,若是 ulr/user,那麼三個頁面將會所有匹配到。這樣的設計在必定程度上給咱們提供了便利,好比說一個公共頁面須要渲染好幾個組件的狀況。可是有時候咱們並不想訪問到所有的匹配組件,這個時候就能夠將這些 Route 組件使用 Switch 包裹起來,它將永遠渲染符合匹配項的第一個組件

注意點:

  • Switch 匹配的規則是同一個組中渲染第一個匹配組件,也就是說若是是包裹在兩個不一樣的 Switch 組件中的,會分別渲染匹配到的第一個組件
  • Switch 組件中不能嵌套內置標籤元素,好比 div span,可是能夠嵌套組件,甚至能夠添加 path 屬性進行匹配, 實際上 Route 自己就是組件,可是建議仍是隻嵌套 Route 或者 Redirect 組件

Link 與 NavLink

相信小夥伴們看過前面的示例以後,應該對 Link 不會陌生了。它的做用就是提供聲明式的可訪問導航

Link 經常使用屬性:
  • to:能夠是 String 類型或者具備 pathnamesearchhashstate任何屬性的對象

    pathname: 表示要連接到的路徑的字符串

    search: 表示查詢參數的字符串形式

    hash: 放入網址的 hash

    state: 狀態持續到 location

  • replaceboolean 類型,若是爲 true,點擊連接將替換當前歷史記錄
NavLink 一個特殊版本的 Link,當它與當前 URL 匹配時,爲其渲染元素添加樣式屬性,其用法與 Link 基本相同

注意點:

  • 給渲染元素添加屬性可使用 activeClassName 或者 activeStyle 屬性進行添加,簡單來講就是使用 class 類或者行內樣式
  • NavLink 有一個 exact 屬性,若是爲 true,則僅在位置徹底匹配時才應用 active 的類/樣式

Redirect 組件

顧名思義,重定向組件,組件中的 to 屬性是必須的

屬性:

  • tostring 類型或者一個對象(pathname 屬性是重定向到的 URL
  • pushboolean 類型,當 true 時,重定向會將新地址推入 history 中,而不是替換當前地址,就是經過 history.push 或者 history.replace 實現
  • from:重定向 from 的路徑名,簡單說就是將要進入的 url
  • exact:徹底匹配 from;至關於 Route.exact

這個組件在一些場景中有很好的效果,好比咱們登陸場景,前面咱們介紹過的 Route 組件渲染屬性使用 render 或者 children 的時候,就徹底能夠根據判斷條件執行不一樣的路由跳轉

<!-- 官網示例代碼 -->
<Route exact path='/' render={()=>(
    loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)} />

<!--或者-->
<Route path='/about' children={({match})=>(
    match ? (
        <About />
    ) : (
        <User />
    )
)} />

前面介紹 Switch 組件時,有過它的身影,實際上它能夠和 Switch 組件很好的配合,好比:

<Switch>
    <Redirect from='/user' to='/about' />
    <Route path='/user' render={()=><div>User頁面</div>} />
</Switch>

須要注意的地方:

  • from 屬性只能用於在 Redirect 內部渲染 Switch 時匹配地址
  • Redirect 組件中 from 匹配的 Route 要在前面定義
<!--錯誤姿式,這樣是沒有效果的-->
<Route path='/user' render={()=><div>User頁面</div>} />
<Redirect from='/user' to='/about' />

withRouter

默認狀況下,通過路由匹配的組件才擁有路由參數,咱們就能夠在其中使用 編程式導航,好比:

this.props.history.push('/about')

然而,不是全部的組件都是與路由相連的,好比直接在瀏覽器輸入地址打開的。這個時候咱們訪問組件 props 的時候,它是一個空對象,就沒辦法訪問 props 中的 historymatchlocation 等對象

因此 這個時候 withRouter 閃亮登場

withRouter 的用法很簡單:

import React, { Component } from 'react';
<!--引入-->
import { Route, Link, Switch, withRouter } from 'react-router-dom' 

class App extends Component {
    render() { 
    <!-- 沒有使用 withRouter 的時候,是一個空對象-->
        console.log(this.props)
        return ( 
            <div>
                <Link to='/'>Index</Link>
                <Link to='/about'>About</Link>
                <Switch>
                    <Route path='/' exact render={()=> <div>Index頁面</div>} />
                    <Route path='/about' render={()=> <div>About頁面</div>} />
                </Switch>
            </div>
         );
    }
}
 
<!--執行-->
export default withRouter(App)

固然,還有不少種使用方式,好比經過 withRouter 監聽 loaction 對象改變文檔標題或者配合 redux 使用等等

詳見 示例demo

進一步

瞭解了 react-router 的這些基本知識點,貌似咱們已經能夠寫出來一個用路由搭建的項目了。可是,請暫時停下腳步想一下:在一個項目當中,若是咱們遇到嵌套的路由呢、動態參數的路由呢?固然,只用前面瞭解到的東西,徹底能夠寫出來,但那是在是太 low

match 對象

在解答前面的兩個問題以前,咱們須要先了解一個 match 對象

相信在前面的 withRouter 模塊,小夥伴們已經知道了 match 對象的存在,在動態路由和路由嵌套時,咱們會常常和它打交道

一個 match 對象中包涵了有關如何匹配 URL 的信息

它包含如下屬性:

  • params:與動態路徑的 URL 對應解析,它裏面包含了動態路由裏面的信息
  • path:用於匹配的路徑模式
  • url:用於匹配部分的 URL
  • isExact - 若是爲 true 匹配整個 URL (沒有結尾字符)

注意點:

  • 若是 Route 沒有 path,那麼將會一直與他最近的父級匹配。這也一樣適用於 withRouter
  • match 對象中的 urlpath ,簡單來講 path 是匹配的規則, url 則是實際匹配到的路徑

動態路由

瞭解了 match 對象,動態路由的定義其實很簡單

<Link to='/video/1'>視頻教程1</Link>
<Link to='/video/2'>視頻教程2</Link>

<Route path='/video/:id' component={Video} />

Route 組件能夠匹配到 Link 連接跳轉的路徑,而後再 match 對象的 params 屬性中就能夠拿到動態數據的具體信息

嵌套路由

React Router 4 再也不提倡中心化路由,取之的是路由存在於佈局和 UI 之間,Route 自己就是一個組件

實現路由嵌套最簡單的方式:

<!--父組件-->
<Route path='/workplace' component={Workplace} />

<!--子組件-->
<Route path='/workplace/money' component={Money} />

固然,使用 match 來進行匹配會更加優雅

<!--父組件-->
<Route path='/video' component={Video} />

<!--子組件-->
<Route path={`${this.props.match.url}/react`} component={ReactVideo} />

注意點:

  • 使用嵌套路由父級不能使用 exact

使用這樣的方式來配置路由規則,咱們就只須要考慮 component 的渲染時機就能夠了。可是,一樣的也會給咱們帶來一些問題,好比說路由規則不是很直觀,尤爲是對於寫過 vue 的小夥伴來講,要是有一個像配置 vue-router 規則的東西就行了。這個時候,咱們能夠試着去了解一個這個東西了 react-router-config

詳見 示例demo

後記

突如其來的結束語

關於 react-router 的基本用法就是想上面介紹的那樣,可是想要探究更多有意思或者更優雅的用法,還須要咱們在具體的項目中去磨練,好比說路由的拆分、按需加載等等一系列東西

若是你也對 React 中的其餘內容感興趣,想要了解更多前端片斷,能夠 點擊這裏 ,歡迎 star 關注

參考

官方文檔

簡明React Router v4教程

相關文章
相關標籤/搜索