- 功能:讓使用者從一個檢視(元件)導航到另一個檢視(元件)
- 前端路由是一套對映規則,在React中,是URL路徑與元件的對應關係
- 使用React路由簡單來說,就是配置路徑和元件
路由的使用
1、安裝路由
npm i -S react-router-dom
2、相關元件
Router元件:包裹整個應用,一個React應用只需要使用一次 Router: HashRouter和BrowserRouter - HashRouter: 使用URL的雜湊值實現 (localhost:3000/#/first) - BrowserRouter:使用H5的history API實現(localhost3000/first)
Link/NavLink元件:用於指定導航連結(a標籤)
- to屬性:會被編譯成 a標籤的href屬性
to='/main' || to='{{pathname='/main'}}'
- activeClassName屬性:指定樣式名
- Link 不會顯示按鈕的高亮顯示, NavLink 來替代它
- 最終Link會編譯成a標籤,
- to屬性:會被編譯成 a標籤的href屬性
Route元件:指定路由展示元件相關資訊(元件渲染)
- path屬性:路由規則,這裡需要跟Link元件裡面to屬性的值一致
- exact屬性:嚴格匹配, 為
true
是表示嚴格匹配,為false
時為正常匹配。 - component屬性:展示的元件
- render屬性:用於頁面元件級別的許可權管理
3、使用
步驟一:定義路由模式
- 主入口index.js中定義路由模式
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './store'
import {HashRouter ar Router} from 'react-router-dom'
ReactDom.render(
<Provider store={store}>
<Router>
<App/>
</Router>
<Provider>,
document.getElementById('root')
)
步驟二:元件內渲染路由 + 路由宣告式導航
- 匯入渲染元件
- Route路由渲染元件
- 使用Link或NavLink元件完成宣告式導航的定義
import React, { Component } from 'react'
import { Route, Link } from 'react-router-dom'
<!-- 匯入渲染元件 -->
const Home = () => (<div>Home</div>)
const About = () => (<div>About</div>)
const DashBord = () => (<div>DashBord</div>)
class App extends Component {
render() {
return (
<>
<ul>
{/* 宣告導航*/ }
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="{{pathname:'/dashbord'}}">DashBord</Link></li>
</ul>
{/*
path:可訪問的url路徑
component:匹配成功的渲染的元件
exact:嚴格匹配模式
Route元件中匹配成功,渲染會自動在this.props中新增路由導航相關屬性方法
*/ }
<Route path="/" exact component={Home}></Route>
<Route path="/about" component={About}></Route>
<Route path="/dashbord" component={DashBord}></Route>
</>
);
}
}
export default App;
路由的擴充套件
1、路由引數
在Route定義渲染元件時給定動態繫結的引數
- params:在路由目標頁面中
- 動態路由定義:
<Route path='/detail/:id' component={Detail}>
- 傳遞:
<NavLink to='/detail/2'>
- 獲取:this.props.match.params
- 動態路由定義:
- query:通過位址列中的 ?key=value&key=value,
- 傳遞:
<NavLink to='/detail?name=cc'>
- 獲取:this.props.location.search
- 備註:獲取到的search是urlencoded編碼字串,需要藉助querystring解析
- 傳遞:
- state:隱式轉參,用於資料的收集
- 傳遞:
<NavLink to='{{pathname:/detail?name=cc,state:{age:20}}}'>
- 獲取:this.props.location.state
- 作用:埋點---收集資料統計
- 傳遞:
2、switch元件
- 通常情況下, path和component是一一對應的關係.
- Switch可以提高路由匹配效率(單一匹配).
- 為了更好地匹配規則,輕易不要捨棄
。 - Redirect:路由從定向,一般寫在所有路由註冊的最下方,當所有路由都無法匹配時,跳轉到Redirect指定的路由
import { Route,Switch } from 'react-router-dom'
<div>
<div>
<ul>
<li>
<Link to="/Guide/ContactUs">ContactUs</Link>
</li>
</ul>
</div>
<Switch>
<Route path="/Guide/ContactUs" component={ ContactUs } ></Route>
<Route path="/Guide/ContactUs" component={ ContactUs } ></Route>
<Redirect from="/" to="/public"></Redirect>
</Switch>
</div>
3、Route元件三種渲染方式
1、component
- 引數:物件
<Route path='/home' component={home}/>
- 直接使用元件類--使用最多的方式
- 缺點:不能把父元件中的資料通過props傳遞給路由元件中
- 引數:函式
<Route path='/home' component={()=><home/>} />
- 使用函式,可以寫條件判斷,根據條件來渲染不同的元件
- 可以通過props來完成父元件中的資料向路由渲染元件傳遞
- 缺點:每次匹配路由成功都會從新建立元件---效率低下,不建議使用
<Route path='/home' component={()=>{
return <Home count={this.state.count}/>
}}/>
2、render
<Route path="/home" render={props=><Home />} />
- render方式渲染,使用函式方式
- 如果匹配相同,則不重新建立,效率高
- 建議如果元件物件方式渲染(函式方式)推薦使用render
<Route path='/home' render={()=>{ if(this.state.count==1){ return <Home1 count={this.state.count}/> }else{ retutn <Home2/> } }}/>
3、children
- 元件物件方式:必須匹配到path的路由規則才渲染和render與component一樣
<Route path="/about" children={<About />} />
- 函式方式:不管是否和path匹配都渲染
- match為null表示當前路由規則和path不匹配,如果為物件則匹配成功
<Route path="/about" children={match=>{ if(match){ return <div>children渲染</div> } }} />
3種渲染區別總結 比較一
- component:可以使用元件類渲染或內聯式方式渲染
- render:只能使用函式
- children:使用函式或直接使用元件物件
比較二
- component:內聯式渲染方式在每次匹配路由成功後都將建立一個新元件
- render,children不會,所以用內聯式方式建議使用後兩者,內聯方式渲染元件,推薦用render
比較三
- children的值是一個函式時,無論當前地址和path路徑匹不匹配,都將會執行children對應的函式,當children的值為一個元件時,當前地址和path不匹配時,路由元件不渲染
- children函式方式渲染,會在形參中接受到一個物件,物件中match屬性如果當前地址匹配成功返回物件,否則null
4、程式設計式路由導航
藉助this.prosp.history
物件上的API對操作路由跳轉、前進、後退
- this.prosp.history.push()
- this.prosp.history.replace()
- this.prosp.history.goBack()
- this.prosp.history.goForward()
- this.prosp.history.go()
**注:**預設元件中沒有this.props.history方法,需要通過withRouter高階元件(裝飾器)來進行包裹,才能得到。
this.props.history.push(path)
或
this.props.history.push({
pathname:'',
search:'',
state:{}
})
路由監聽 在App.jsx元件中可以新增路由監聽
constructor(props) {
super(props);
this.props.history.listen(route=>console.log(route))
}
5、withRouter高階元件
作用:把不是通過路由切換過來的元件中,將react-router 的 history、location、match 三個物件傳入props物件上
- 如果在你想在一般元件使用 路由元件所特有的API 時, 就要藉助 withRouter
- withRouter可以加工一般元件, 讓一般元件具備路由元件所特有的API
- withRouter的返回值是一個新元件
- 引入withRouter
import { withRouter} from 'react-router-dom'
執行一下withRouter
export default withRouter(Cmp)`
import React, { Component } from 'react'
import {withRouter} from 'react-router-dom'
class Header extends Component {
// 回退
back = () => {
this.props.history.goBack()
}
// 前進
forward = () => {
this.props.history.goForward()
}
/// go
go = () => {
this.props.history.go(2)
}
render() {
// console.log('一般元件',this.props)
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前進</button>
<button onClick={this.go}>go</button>
</div>
)
}
}
export default withRouter(Header)
6、自定義路由
- 定義一個普通元件可以是類元件也可以是函式式元件
- 父元件能向子元件傳值 props
- 不管路由規則是否匹配都要顯示元件 Route children渲染方式(函式式)
- 注意點:react中元件是大寫字母開頭 html也是元件
import React from 'react'
import {withRouter,Route} from 'react-router-dom'
const MyLink = props=>{
const gourl=()=>{
props.history.push(props.to)
}
const Tag=props.tag||'a'
const Active=props['active-class']||'router-active-class'
return (
<Route path={props.to} children={({match})=>{
if(match){
return <Tag style={{color:'red'}} Onclick={gourl}>{props.children}</Tag>
}
return <Tag onClick={gourl}>{props.children}</Tag>
}}>
)
}
export default withRouter(MyLink)
7、多級路由
在有一些功能中,往往請求地址的字首是相同的,不同的只是後面一部份,此時就可以使用多級路由(路由巢狀)來實現此路由的定義實現。
例: 路由規則如下 admin/index admin/user
當前組建的請求uri地址(父元件路由uri)
let pathname=this.props.match.path
return(
<Link to=`${pathname}/index`>使用者首頁</Link>
<Link to=`${pathname}/list`>使用者列表</Link>
寫在admin元件內,admin元件通過route來進行渲染
<Route path={`${pathname}/index`} component={main}/>
<Route path={`${pathname}/list`} component={index}/>
)
8、重定向與404
重定向 from從哪裡來 to重定向到何處去
<Redirect from="/home" to="/" />
404設定
<Route component={Notfound} />
預設:匹配規則是從上項下的,一隻匹配下去 switch元件:解決一直匹配問題,只要有一個符合;路由規則就停止匹配
<Switch>
<Route exact path='/news' component={index}/>
<Route path='/news/:id' component={Newss}/>
重定向from來源,to跳轉的頁面
<Redirect exact from='/' to='/news'>
<Route component={notFound}>
</Switch>
React Router 基本原理
React Router依賴於history.js
,它是一個獨立的第三方js庫。可以用來相容在不同瀏覽器、不同環境下對歷史記錄的管理,擁有統一的API。
- 老瀏覽器的history: 通過
hash
來儲存在不同狀態下的history
資訊,對應createHashHistory
,通過檢測location.hash
的值的變化,使用location.replace
方法來實現url跳轉。通過註冊監聽window
物件上的hashChange
事件來監聽路由的變化,實現歷史記錄的回退。 - 高版本瀏覽器: 利用HTML5裡面的history,對應
createBrowserHistory
, 使用包括pushState
,replaceState
方法來進行跳轉。通過註冊監聽window
物件上的popstate
事件來監聽路由的變化,實現歷史記錄的回退。 - node環境下: 在記憶體中進行歷史記錄的儲存,對應
createMemoryHistory
。直接在記憶體裡push
和pop
狀態。