0x000 概述
上一章使用的是自己實現的route
,當然已經有現成的庫給我們用了,那就是react-route。
0x001 history Api
說明
在說這個庫之前,得先對history
新的api
做一個瞭解
-
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
但是網絡請求卻沒有發出
-
-
window.history.state
:該變量可以獲取到跳轉當前所處state
時傳入的data
: -
window.onpopstate
:這是一個事件,可以設置監聽器,監聽狀態被pop
出來的時候的事件,其中go
、back
會觸發該事件 - 總結
根據以上幾個特性,就可以和上一章一樣,做出一個基於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()
查看瀏覽器
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') )
- 效果
-
說明
-
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
屬性。 -
history
通過history
庫來做location
監聽和跳轉 -
withRoute
是一個HOC
,爲App
組件注入了history
對象和路由相關的屬性,這樣可以屏蔽路由的存在,將App
組件變成一個純粹的組件 -
Router
組件接管了histoy
對象,在該組件中完成了history
的監聽和路由的渲染
-
0x004 react-route-dom
上面的調用太複雜了,需要手動創建history
、調用this.props.history.push('/index')
跳轉,那有沒有簡單點的呢?那就是react-router-dom,這個庫封裝了react-route
、history
庫,並提供了幾個實用的組件
- 源碼
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')
)
-
說明:
- 使用
BrowserRouter
替代Router
,並且不再手動創建history
- 使用
Link
直接跳轉 - 該庫是在
react-route
和history
庫的基礎之上封裝的,只是爲了在dom
環境下快速調用,並且提供了一個更加實用的組件而已,不能應爲這個庫而忘記了本質。
- 使用
0x005 總結
看透它,然後掌握它