React Rouer 使用教程

前言

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

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

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

安裝

國際慣例,首先我們需要安裝

npm install --save react-router-dom 

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

React Router 現在已經被劃分成了三個包:react-routerreact-router-domreact-router-native

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

因爲我們需要開發一個 web 應用,所以直接安裝 react-router-dom 就可以了

初體驗

首先,讓我們通過一個小小的示例來感知一下 react-router

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 中高頻率出現的概念

常用組件

Router 組件

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

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教程

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