Router入門0x203: react、react-route、react-route-dom

0x000 概述

上一章使用的是自己實現的route,當然已經有現成的庫給我們用了,那就是react-route

0x001 history Api說明

在說這個庫之前,得先對history新的api做一個瞭解

  1. window.history.pushState(data,title,?url)

    • data:數據
    • title:標題
    • url:地址

      當我們調用該函數的時候,將改變地址欄的地址,但是卻不會導致頁面重新去後臺獲取,如下圖操作,在第一次初始化完成之後,我們依次調用

      window.history.pushState({name:'a'},'','a')
      window.history.pushState({name:'b'},'','b')
      window.history.pushState({name:'c'},'','c')
      window.history.pushState({name:'d'},'','d')

      將會看到地址欄分別變成了:

      https://github.com/a
      https://github.com/b
      https://github.com/c
      https://github.com/d

      但是網絡請求卻沒有發出

      clipboard.png

  2. window.history.state:該變量可以獲取到跳轉當前所處state時傳入的data:

    clipboard.png

  3. window.onpopstate:這是一個事件,可以設置監聽器,監聽狀態被pop出來的時候的事件,其中goback會觸發該事件

    clipboard.png

  4. 總結
    根據以上幾個特性,就可以和上一章一樣,做出一個基於history模式的路由庫了

0x002 history庫說明

history是一個針對該特性封裝的庫,以下是示例代碼

import createHistory from 'history/createBrowserHistory'

const history = createHistory()

// 監聽 location 的變化
const unlisten = history.listen((location, action) => {
    // location is an object like window.location
    console.log(action, location.pathname, location.state)
})
// 修改 location
history.push("/home", { some: "state" })
// 取消監聽
unlisten()

查看瀏覽器

clipboard.png

0x003 react-route

react-route+history+react就可以形成一個套餐了
  • 源碼

    import React from 'react'
    import ReactDom from 'react-dom'
    import { Router, Route, Switch,withRouter } from 'react-router'
    import createHistory from 'history/createBrowserHistory'
    
    class App extends React.Component{
        render(){
            console.log(this)
            return(
                <div>
                    <div>
                        <button className="btn btn-primary" onClick={()=>{this.props.history.push('/index')}}>首頁</button>
                        <button className="btn btn-primary" onClick={()=>{this.props.history.push('/article')}}>文章</button>
                        <button className="btn btn-primary" onClick={()=>{this.props.history.push('/mine')}}>我的</button>
                    </div>
                    <hr/>
                    <Switch>
                        <Route path='/index' component={()=>({render:()=><p>首頁</p>})}></Route>
                        <Route path='/article' component={()=>({render:()=><p>文章</p>})}></Route>
                        <Route path='/mine' component={()=>({render:()=><p>我的</p>})}></Route>
                    </Switch>
                </div>
            )
        }
    }
    
    const history = createHistory()
    
    let MyApp=withRouter(App)
    
    ReactDom.render(
        <Router history={history}>
            <MyApp/>
        </Router>,
        document.getElementById('app')
    )
  • 效果
    圖片描述
  • 說明

    1. App組件說明
      App組件是跟組件,所有的組件都掛載在這個組件之下,在這個組件中,使用了兩個react-route的組件,一個是Switch,用來在路由變化的時候切換顯示的路由;一個是Route組件,一個Route代表一個頁面,也代表一個組件,這裏用了三個Route,每個Route對應一個路由,也對應一個組件,這裏的組件爲了方便,直接用匿名函數實現,分別是:

      ()=>({render:()=><p>首頁</p>}) // 對應`/index`
      ()=>({render:()=><p>文章</p>}) // 對應`/article`
      ()=>({render:()=><p>我的</p>}) // 對應`/mine`

      當我們點擊相應的按鈕的時候,將會調用this.props.history.push('${path}')來跳轉到對應的頁面,其中${path}是我們設置的Route組件的path屬性。

    2. history
      通過history庫來做location監聽和跳轉
    3. withRoute是一個HOC,爲App組件注入了history對象和路由相關的屬性,這樣可以屏蔽路由的存在,將App組件變成一個純粹的組件
    4. Router組件接管了histoy對象,在該組件中完成了history的監聽和路由的渲染

0x004 react-route-dom

上面的調用太複雜了,需要手動創建history、調用this.props.history.push('/index')跳轉,那有沒有簡單點的呢?那就是react-router-dom,這個庫封裝了react-routehistory庫,並提供了幾個實用的組件
  • 源碼

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

class App extends React.Component {
    render() {
        return (
            <div>
                <div>
                    <Link to='/index'>首頁</Link>
                    <Link to='/article'>文章</Link>
                    <Link to='/mine'>我的</Link>
                </div>
                <hr/>
                <Switch>
                    <Route path='/index' component={() => ({render: () => <p>首頁</p>})}></Route>
                    <Route path='/article' component={() => ({render: () => <p>文章</p>})}></Route>
                    <Route path='/mine' component={() => ({render: () => <p>我的</p>})}></Route>
                </Switch>
            </div>
        )
    }
}

let MyApp = withRouter(App)


ReactDom.render(
    <BrowserRouter>
        <MyApp/>
    </BrowserRouter>,
    document.getElementById('app')
)
  • 說明:

    1. 使用BrowserRouter替代Router,並且不再手動創建history
    2. 使用Link直接跳轉
    3. 該庫是在react-routehistory庫的基礎之上封裝的,只是爲了在dom環境下快速調用,並且提供了一個更加實用的組件而已,不能應爲這個庫而忘記了本質。

0x005 總結

看透它,然後掌握它

0x006 資源

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