前言
路由是React項(xiàng)目中相當(dāng)重要的概念覆获,對(duì)于功能較為復(fù)雜的網(wǎng)頁(yè)來(lái)說(shuō)渔彰,必然會(huì)涉及到不同功能間的頁(yè)面跳轉(zhuǎn)欧芽,本篇文章將對(duì)React官方維護(hù)的路由庫(kù)
React-Router-Dom
的使用和常用組件進(jìn)行講解症脂,同時(shí)對(duì)路由組件傳遞param參數(shù)的方式進(jìn)行講解织鲸,希望對(duì)各位讀者有所參考句占。
一沪摄、了解SAP和路由的概念
SAP(single page web application)的意思是單頁(yè)Web應(yīng)用,正如前言所說(shuō)纱烘,一般來(lái)說(shuō)功能較為復(fù)雜都會(huì)涉及到頁(yè)面跳轉(zhuǎn)的功能杨拐,而傳統(tǒng)的前端頁(yè)面跳轉(zhuǎn)往往是利用<a/>
標(biāo)簽進(jìn)行跳轉(zhuǎn),這種方式雖然可以實(shí)現(xiàn)功能擂啥,但是每次跳轉(zhuǎn)到新的頁(yè)面都會(huì)重新對(duì)頁(yè)面的元素進(jìn)行加載哄陶,這樣其實(shí)對(duì)于用戶來(lái)說(shuō)是不太友好的。而單頁(yè)Web應(yīng)用則較好的解決了這個(gè)問(wèn)題哺壶,因?yàn)镾AP整個(gè)應(yīng)用都是在一個(gè)頁(yè)面上進(jìn)行的屋吨,每次的頁(yè)面跳轉(zhuǎn)只涉及到頁(yè)面中對(duì)應(yīng)組件(模塊)的更新操作,這樣就在一定程度上讓頁(yè)面不需要加載重復(fù)的頁(yè)面元素山宾。
再說(shuō)說(shuō)路由
路由其實(shí)可以理解為是一個(gè)映射關(guān)系至扰,即路徑到組件或者函數(shù)的對(duì)應(yīng)關(guān)系,比如說(shuō)/home
這個(gè)路徑對(duì)應(yīng)著Home
這個(gè)首頁(yè)組件塌碌,在React中渊胸,有react-router-dom
這個(gè)官方維護(hù)的組件庫(kù)來(lái)幫助我們處理項(xiàng)目中的路由問(wèn)題,需要注意的是台妆,我們用create-react-dom
創(chuàng)建的react項(xiàng)目翎猛,默認(rèn)是沒有react-router-dom
的,所以需要我們自己再額外下載到項(xiàng)目中接剩。
二切厘、路由入門小案例
當(dāng)前存在Home
、About
兩個(gè)組件懊缺,我們希望在頁(yè)面上的導(dǎo)航欄中實(shí)現(xiàn)點(diǎn)擊對(duì)應(yīng)標(biāo)簽疫稿,即可在頁(yè)面上顯示對(duì)應(yīng)組件的內(nèi)容培他。
Home組件:
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<h3>我是Home的內(nèi)容</h3>
)
}
}
About組件:
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<h3>我是About的內(nèi)容</h3>
)
}
}
App組件
省略import...
export default class App extends Component {
render() {
return (
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<a class="list-group-item" to='/about'>About</a>
<a class="list-group-item" to='/home'>Home</a>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
</div>
</div>
</div>
</div>
</div>
)
}
}
步驟一:下載路由組件庫(kù)
install i react-router-dom
步驟二:引用Link標(biāo)簽,替代<a>
標(biāo)簽進(jìn)行跳轉(zhuǎn):
需要注意的是<Link>其實(shí)本質(zhì)上也是<a>
標(biāo)簽遗座,只是說(shuō)它阻止了a標(biāo)簽?zāi)J(rèn)的跳轉(zhuǎn)動(dòng)作舀凛,但保留了其修改瀏覽器URL路徑的能力。
import {Link,Router, Route} from 'react-router-dom'
...
export default class App extends Component {
render() {
return (
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
{/*
使用Link標(biāo)簽代替 a 標(biāo)簽途蒋,這一步是用于實(shí)現(xiàn)第一步:瀏覽器URL的變更
*/}
<Link class="list-group-item" to='/about'>About</Link>
<Link class="list-group-item" to='/home'>Home</Link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
</div>
</div>
</div>
</div>
</div>
)
}
}
步驟三:定義路由對(duì)應(yīng)要跳轉(zhuǎn)的組件:
這一步也比較好理解猛遍,前端路由器(會(huì)在步驟四配置)會(huì)自動(dòng)檢測(cè)到瀏覽器的url發(fā)生了變化,此時(shí)就會(huì)拿新的url地址到路由表中進(jìn)行匹配号坡,步驟三定義的就是和url匹配成功的路由懊烤,將顯示對(duì)應(yīng)哪個(gè)組件。
import {Link,Router, Route} from 'react-router-dom';
export default class App extends Component {
render() {
return (
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
{/*
使用Link標(biāo)簽代替 a 標(biāo)簽宽堆,這一步是用于實(shí)現(xiàn)第一步:瀏覽器URL的變更
*/}
<Link class="list-group-item" to='/about'>About</Link>
<Link class="list-group-item" to='/home'>Home</Link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
{/*
在App.js中腌紧,定義路由,路由規(guī)定了path對(duì)應(yīng)跳轉(zhuǎn)的組件
*/}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
步驟四:在最外層的index.js中配置前端路由器
這里可以使用Router組件畜隶,但我們一般是使用功能更為強(qiáng)大的BrowerRouter或者HashRouter壁肋。
import React from 'react'
import ReactDOM from 'react-dom'
// 注意,我們一般不直接引入Router代箭,而是引入 BrowserRouter 或者 HashRouter
import {BrowserRouter} from 'react-router-dom'
import App from './App'
ReactDOM.render(<BrowserRouter><App/></BrowserRouter>,document.getElementById('root'))
最后墩划,我們?cè)賹?duì)React路由實(shí)現(xiàn)的原理做一個(gè)小結(jié):
(1)使用<Link>等標(biāo)簽實(shí)現(xiàn)對(duì)瀏覽器path的操作(本質(zhì)上是對(duì)BOM對(duì)象的history進(jìn)行操作)
(2)當(dāng)前端路由器檢測(cè)到瀏覽器的path發(fā)生了變化涕刚,就會(huì)到路由中對(duì)新的路徑進(jìn)行匹配
三嗡综、路由的常用組件
(一)NavLink標(biāo)簽
NavLink組件是在Link組件的基礎(chǔ)上做了高亮特效的增強(qiáng),在我們快速入門的案例中杜漠,我們想要增加一個(gè)功能极景,當(dāng)我點(diǎn)擊導(dǎo)航欄的某個(gè)標(biāo)簽時(shí),對(duì)應(yīng)的標(biāo)簽要有高亮顯示的效果驾茴。比較容易地我們會(huì)想到給每個(gè)標(biāo)簽增加一個(gè)是否高亮的flag盼樟,當(dāng)滿足選中的條件時(shí),即將高亮的樣式追加到頁(yè)面的標(biāo)簽上锈至。
而NavLink組件可以說(shuō)是幫我們簡(jiǎn)化了上述的操作晨缴,我們只需要傳入activeClassName指定具體追加的屬性即可。需要注意的是峡捡,如果追加的高亮屬性命名是 active時(shí)击碗,可以省略。
上一小節(jié)的案例可以優(yōu)化為:
import {NavLink,Route} from 'react-router-dom'们拙;
export default class App extends Component {
render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<NavLink activeClassName="active" className="list-group-item" to='/about'>About</NavLink>
<NavLink activeClassName="active" className="list-group-item" to='/home'>Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
(二)Switch組件
當(dāng)路由中出現(xiàn)了2個(gè)或者2個(gè)以上的path同時(shí)匹配的情況稍途,那么實(shí)際上對(duì)應(yīng)的路由組件都會(huì)被渲染。如果我們想要說(shuō)只渲染(掛載)第一個(gè)匹配上的組件的話砚婆,那么我們可以使用<Switch>組件來(lái)解決械拍。
我們先來(lái)看一下未使用Switch組件的情況: /home
對(duì)應(yīng)著2個(gè)組件
export default class App extends Component {
render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Home2}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
我們可以引入Switch組件來(lái)解決這個(gè)問(wèn)題:
export default class App extends Component {
render() {
return (
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Home2}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
(三)Redirect組件
我們?cè)谶M(jìn)入網(wǎng)站的時(shí)候,網(wǎng)站的導(dǎo)航欄中往往會(huì)有一個(gè)默認(rèn)選中的標(biāo)簽,對(duì)于這種場(chǎng)景坷虑,React路由其實(shí)也為我們提供了對(duì)應(yīng)的組件來(lái)幫助我們簡(jiǎn)化開發(fā)甲馋,那就是Redirect組件。我們?cè)诳焖偃腴T的案例中新增加一個(gè)功能迄损,進(jìn)入首頁(yè)后摔刁,默認(rèn)跳轉(zhuǎn)到/about
路徑下。
export default class App extends Component {
render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about" />
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
四海蔽、精準(zhǔn)匹配和模糊匹配
React路由的匹配方式一共有2種共屈,分別是精準(zhǔn)匹配和模糊匹配。
我們知道党窜,要想正確使用react-router-dom來(lái)實(shí)現(xiàn)路由跳轉(zhuǎn)拗引,一共需要更新path和匹配path對(duì)應(yīng)組件這兩步。
精準(zhǔn)匹配很好理解幌衣,就是path的路徑和路由的路徑必須完全相同才能匹配成功矾削。
而模糊匹配,則是只要path能夠覆蓋route的路徑豁护,不需要完全匹配即可匹配成功哼凯。當(dāng) Link標(biāo)簽中定義的path為二級(jí)(或以上級(jí)別)的路由,那么只需要其第一級(jí)的path和Route定義的path一致即可匹配成功楚里;反之断部,如果是Link表中定義的path只是一級(jí)路由,而Route不存在完全匹配的路由班缎,則匹配失敗蝴光。 舉例來(lái)說(shuō),<Link to="/home/a/b"> <Route path="/home" component={Xxxx} />
在模糊匹配的條件下达址,是可以成立的蔑祟。而 <Link to="/home"> <Route path="/home/a/b" component={Xxxx} />
這種情況下是不可以匹配成功的。
我們可以通過(guò)下面的例子來(lái)加深一下對(duì)精準(zhǔn)匹配和模糊匹配的理解:
(一)精準(zhǔn)匹配
常規(guī)的精準(zhǔn)匹配要求沉唠,跳轉(zhuǎn)的路徑和路由中配置的路徑要完全匹配疆虚。由于路由默認(rèn)是模糊匹配,如果需要開啟精準(zhǔn)匹配满葛,需要我們?cè)?code>Route組件中配置exact=true
或者直接簡(jiǎn)寫exact
径簿。精準(zhǔn)匹配使用簡(jiǎn)單,但實(shí)際上纱扭,exact 在實(shí)際應(yīng)用中還是盡量要謹(jǐn)慎使用牍帚,避免出現(xiàn)二級(jí)(n級(jí))路由匹配不到的問(wèn)題出現(xiàn)。(詳見下一節(jié)的嵌套路由)
export default class App extends Component {
render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Route exact path="/about" component={About}/>
<Route exact path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
(二)模糊匹配
在下面的案例中乳蛾,<MyNavLink>
組件(自己對(duì)NavLink組件的封裝)中配置的路徑為/about/test
和/home/test
暗赶,和路由配置的path并不完全一致鄙币。(屬于前者為后者的子集),此時(shí)是可以正常跳轉(zhuǎn)的蹂随。
export default class App extends Component { render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about/test">About</MyNavLink>
<MyNavLink to="/home/test">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
我們可以嘗試著換種方式十嘿,改成<MyNavLink>
配置的路徑是<Route>
組件配置路徑的父集,看組件能夠跳轉(zhuǎn)成功岳锁。
export default class App extends Component { render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Route path="/about/test" component={About}/>
<Route path="/home/test" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
我們可以從上圖中看到绩衷,此時(shí)About組件的內(nèi)容是沒有出來(lái)的,也就是說(shuō)模糊匹配并不支持瀏覽器跳轉(zhuǎn)的url是
<Route>
組件配置路徑的父集這個(gè)情景激率。上述這種情況其實(shí)不難理解咳燕,我們真正去匹配一個(gè)組件時(shí),應(yīng)該是以Route配置為準(zhǔn)乒躺,從父組件(一級(jí)路由)一步一步地匹配到子組件(n級(jí)路由)的招盲。反之,一級(jí)路由下往往可能存在有多個(gè)子路由的可能嘉冒,此時(shí)就必然會(huì)面臨頁(yè)面不知道選擇哪個(gè)子路由作為跳轉(zhuǎn)組件的問(wèn)題曹货。
五、嵌套(多級(jí))路由
隨著組件的復(fù)雜度組件上升讳推,有時(shí)候我們可能會(huì)在組件中嵌套多級(jí)的路由顶籽,現(xiàn)在我們?cè)谏弦恍」?jié)的基礎(chǔ)上,新增一個(gè)需求:在Home組件中中新增2個(gè)組件银觅,并對(duì)2個(gè)組件配置對(duì)應(yīng)的二級(jí)路由礼饱。
這里的話省略2個(gè)新組件的代碼(要的話可以從文章最后的碼云鏈接上面看),直接看App組件和Home組件是怎么配置路由的:
App組件
export default class App extends Component {
render() {
return (
<div>
...
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
Home組件:
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的內(nèi)容</h3>
<ul class="nav nav-tabs">
<li><MyNavLink to="/home/news">News</MyNavLink></li>
<li><MyNavLink to="/home/messages">Message</MyNavLink></li>
</ul>
<Route path="/home/news" component={News} />
<Route path="/home/messages" component={Message} />
</div>
)
}
}
我們可以看到设拟,在Home組件中慨仿,我們<NavLink>組件和<Route>組件對(duì)應(yīng)的路由都是二級(jí)路由久脯,前者很好理解纳胧,<NavLink>
的配置的to屬性表示接下來(lái)瀏覽器將要跳轉(zhuǎn)的路徑,單純地寫/new
的路徑實(shí)際的請(qǐng)求結(jié)果將為:localhost:8080/new
帘撰,不會(huì)帶上上一級(jí)的路由跑慕。
而Home組件的Route雖然是嵌套在App組件中的路由中,但是對(duì)應(yīng)的一級(jí)路由還是必須寫的摧找。因?yàn)槁酚善髟谄ヅ涞臅r(shí)候核行,是根據(jù)路由注冊(cè)的層級(jí)/時(shí)機(jī)來(lái)逐層匹配的,也就是說(shuō)蹬耘,/news 會(huì)先去App.js中的路由中進(jìn)行匹配芝雪,如果匹配不到,那么是到達(dá)不了這個(gè)頁(yè)面的路由的综苔,所以這時(shí)惩系,就需要在Link標(biāo)簽中使用二級(jí)路由了位岔。
所以說(shuō),如果在父路由中使用了精準(zhǔn)匹配堡牡,那么對(duì)于子路由的請(qǐng)求基本上都會(huì)被攔截下來(lái)抒抬,使用不了的。
六晤柄、組件路由傳遞參數(shù)
在上面的講解中擦剑,我們知道了組件如何進(jìn)行跳轉(zhuǎn),但是如果我們需要組件在跳轉(zhuǎn)過(guò)程中攜帶參數(shù)到下一個(gè)組件中芥颈,我們可以怎么實(shí)現(xiàn)呢惠勒?常見的組件路由傳遞參數(shù)的方式有三種,分別是通過(guò)params參數(shù)傳遞爬坑、利用search屬性傳遞捉撮、利用state屬性傳遞,下面我們就來(lái)看一下這三種方式的具體使用吧妇垢。
(一)通過(guò)params進(jìn)行參數(shù)傳遞
步驟一:在<Link>組件上傳遞參數(shù)
一般來(lái)說(shuō)巾遭,我們會(huì)使用類似于/${id}
的方式來(lái)傳遞值
<NavLink to={`/home/messages/details/${messageObj.id}/${messageObj.title}`}>xxx</NavLink>
步驟二:在路由上寫好每個(gè)屬性對(duì)應(yīng)匹配的值
步驟一中雖然傳遞了多個(gè)參數(shù),但是我們并不知道每個(gè)參數(shù)對(duì)應(yīng)的key是什么闯估,所以需要先規(guī)定好每個(gè)參數(shù)對(duì)應(yīng)的key灼舍。
<Route path={'/home/messages/details/:id/:title'} component={Details}/>
步驟三:在目標(biāo)組件中使用this.props.match
來(lái)獲取傳遞的參數(shù)
export default class Details extends Component {
state = {
details: [
{id:'01',comment:'你好,我的祖國(guó)'}
...
]
}
render() {
const {details} = this.state;
const {params} = this.props.match;
const detailofMessage = details.find((detailObj)=>{
return detailObj.id === params.id
})
return (
<ul>
<li>ID: {detailofMessage.id}</li>
<li>Title: {params.title}</li>
<li>Comment: {detailofMessage.comment}</li>
</ul>
)
}
}
為什么通過(guò)props可以獲取到參數(shù)呢涨薪?我們不妨打印一下this.props
看一下此時(shí)的Details 組件到底接收了哪些信息骑素。
我們可以看到,此時(shí)組件的props屬性中刚夺,有著三個(gè)屬性献丑,分別是history
,location
和match侠姑,而
match`屬性中已經(jīng)幫我們把傳遞的參數(shù)封裝成為一個(gè)對(duì)象了创橄。
(二)組件路由通過(guò)search屬性傳遞參數(shù)
這種方式基本上和我們常見的在url地址上進(jìn)行參數(shù)拼接是一樣的,這種方式寫法較為簡(jiǎn)單莽红,只需要在 Link 標(biāo)簽中定義好key=value形式參數(shù)拼接妥畏,然后在實(shí)際的組件中,直接從prop屬性中獲取安吁,調(diào)用querystring(或者其他處理字符串轉(zhuǎn)對(duì)象的函數(shù)庫(kù))處理參數(shù)醉蚁,并封裝成對(duì)象返回即可
步驟一:在<Link>
組件上實(shí)現(xiàn)參數(shù)的拼接
<NavLink to={`/home/messages/details?id=${messageObj.id}&title=${messageObj.title}`}>xxx</NavLink>
步驟二:配置路由(其實(shí)這一步可以省略,因?yàn)檫@種方式下的傳參并不需要額外對(duì)路由進(jìn)行配置)
<Route path={'/home/messages/details'} component={Details}/>
步驟三:在實(shí)際組件中獲取傳遞的參數(shù)
我們先來(lái)看一下此時(shí)目標(biāo)組件接收到的props
參數(shù)是什么?
我們可以發(fā)現(xiàn)鬼店,此時(shí)
props.location.search
屬性中把我們步驟一的參數(shù)都封裝了進(jìn)去网棍,但是這種方式封裝的參數(shù)是字符串形式的,我們并不能直接使用妇智,而是要借助queryString
庫(kù)來(lái)幫助我們把字符串解析成對(duì)象滥玷。
import React, { Component } from 'react'
// querystring 是腳手架初始化的時(shí)候自帶的函數(shù)庫(kù)捌锭,能幫助我們分解和生成key=value形式的對(duì)象
import qs from 'querystring'
export default class Details extends Component {
state = {
details: [
{id:'01',comment:'你好,我的祖國(guó)'}
...
]
}
render() {
console.log('this.props',this.props)
const {details} = this.state;
const {search} = this.props.location;
// parse能將字符串轉(zhuǎn)為key:value形式的對(duì)象
const messageObj = qs.parse(search.slice(1));
const detailofMessage = details.find((detailObj)=>{
return detailObj.id === messageObj.id
})
return (
<ul>
<li>ID: {detailofMessage.id}</li>
<li>Title: {messageObj.title}</li>
<li>Comment: {detailofMessage.comment}</li>
</ul>
)
}
}
(三)通過(guò)state屬性來(lái)進(jìn)行參數(shù)的傳遞
這種形式的參數(shù)傳遞很有意思罗捎,和前兩種傳遞參數(shù)的方式不同观谦,這種方式傳遞的參數(shù)是不會(huì)在瀏覽器中顯式的展示的,同時(shí)桨菜,即使刷新頁(yè)面豁状,路由子頁(yè)面的數(shù)據(jù)還是不會(huì)消失。原因是react路由器幫我們對(duì)維護(hù)了history對(duì)象(history對(duì)象中又維護(hù)了location對(duì)象,所以也就有了state對(duì)象)
步驟一:在<Link>組件上傳遞參數(shù)
需要注意的是倒得,和其他兩種方式不同泻红,這里的話to
屬性并不是直接傳一個(gè)字符串,而是傳了一個(gè)對(duì)象霞掺,對(duì)象中包含了pathname
以及state
谊路。
<NavLink to={{pathname:'/home/messages/details',state:{id:messageObj.id,title:messageObj.title}}}>xxx</NavLink>
步驟二:配置路由(其實(shí)這一步可以省略,因?yàn)檫@種方式下的傳參并不需要額外對(duì)路由進(jìn)行配置)
<Route path={'/home/messages/details'} component={Details}/>
步驟三:在具體組件中獲取傳遞的參數(shù)
和之前一樣菩彬,我們先在目標(biāo)組件中將接受到的prpos
進(jìn)行打印輸出缠劝,我們可以看到,此時(shí)在location.state
屬性中骗灶,我們可以獲取到我們?cè)诓襟E一中傳遞的參數(shù)惨恭。
export default class Details extends Component {
state = {
details: [
{id:'01',comment:'你好,我的祖國(guó)'}
...
]
}
render() {
const {details} = this.state;
const {id,title} = this.props.location.state;
const detailofMessage = details.find((detailObj)=>{
return detailObj.id === id
})
return (
<ul>
<li>ID: {detailofMessage.id}</li>
<li>Title: {title}</li>
<li>Comment: {detailofMessage.comment}</li>
</ul>
)
}
}
七耙旦、push和replace跳轉(zhuǎn)和編程式路由
(一)push和replace跳轉(zhuǎn)的區(qū)別
我們知道脱羡,url跳轉(zhuǎn)方式可以有2種,一種是push(把本次操作記錄推入history的棧中)免都,還有一種是replace(把上一次操作記錄替換成本次操作記錄)锉罐。<Link>
組件默認(rèn)使用的跳轉(zhuǎn)方式是push
,如果想使用replase進(jìn)行跳轉(zhuǎn)绕娘,我們可以通過(guò)在組件上新增replace=true
或者是使用簡(jiǎn)寫方式replace
來(lái)進(jìn)行修改脓规。
我們?cè)谏弦恍」?jié)的基礎(chǔ)上,新增一個(gè)新的需求业舍,每次跳轉(zhuǎn)到Details組件時(shí)抖拦,都使用replace這種跳轉(zhuǎn)方式
<NavLink replace to={{pathname:'/home/messages/details',state:{id:messageObj.id,title:messageObj.title}}}>xxx</NavLink>
這個(gè)特性比較簡(jiǎn)單,這里就不使用圖來(lái)表示了...
(二)編程式路由
除了使用路由組件進(jìn)行跳轉(zhuǎn)之外舷暮,其實(shí)我們自己也可以利用事件處理函數(shù)來(lái)走路由跳轉(zhuǎn)和參數(shù)傳遞的功能。
go & goBack & goForward
在路由組件中噩茄,我們可以通過(guò)this.prop.history
獲取到history對(duì)象下面,然后使用對(duì)象對(duì)應(yīng)的API實(shí)現(xiàn)(歷史)路徑的跳轉(zhuǎn)。簡(jiǎn)單理解的話绩聘,就是通過(guò)路由組件的history對(duì)象沥割,實(shí)現(xiàn)頁(yè)面前進(jìn)鞋邑、后退的功能枷邪。
export default class Message extends Component {
state = {...}
// 前進(jìn)+1
forward = ()=>{
this.props.history.goForward();
}
// 后退+1
back = ()=>{
this.props.history.goBack();
}
// 后退+2
go = ()=>{
this.props.history.go(-2);
}
render() {
const { messages } = this.state;
return (
<div>
...
<button onClick={this.forward}>前進(jìn)</button>
<button onClick={this.back}>后退</button>
<button onClick={this.go}>后退+2</button>
</div>
)
}
}
通過(guò)history對(duì)象主動(dòng)調(diào)用push/replace
方法
我們可以在路由組件中通過(guò)this.props.history
獲取到history對(duì)象后,通過(guò)主動(dòng)調(diào)用push或者replace方法來(lái)進(jìn)行路由的跳轉(zhuǎn),需要注意的是陌宿,當(dāng)通過(guò)編程式事務(wù)主動(dòng)進(jìn)行路由跳轉(zhuǎn)時(shí),對(duì)應(yīng)的參數(shù)需要和之前一樣窑眯,根據(jù)傳遞方式的不同來(lái)定義:
export default class Message extends Component {
state = {...}
pushShow = (id,title)=>{
方式1梭伐,采用 params 參數(shù)傳遞
// this.props.history.push(`/home/messages/details/${id}/${title}`)
方式2, 采用 search 參數(shù)傳遞
// this.props.history.push(`/home/messages/details?id=${id}&title=${title}`)
方式3,采用state 參數(shù)傳遞 (state中的id和title采用了簡(jiǎn)寫方式蚀苛,完整寫法應(yīng)該是id:id,title:title)
this.props.history.push({pathname:'/home/messages/details',state:{id,title}})
}
replaceShow = (id,title) =>{
方式1在验,采用 params 參數(shù)傳遞
// this.props.history.replace(`/home/messages/details/${id}/${title}`)
方式2: 采用 search 參數(shù)傳遞
// this.props.history.replace(`/home/messages/details?id=${id}&title=${title}`)
方式3,采用state 參數(shù)傳遞
this.props.history.replace({pathname:'/home/messages/details',state:{id,title}})
}
...
render() {
const { messages } = this.state;
return (
<div>
<div>
<ul>
{
messages.map((messageObj) => {
return (
<li key={messageObj.id}>
{/* 傳遞state參數(shù) */}
<NavLink replace to={{ pathname: '/home/messages/details', state: { id: messageObj.id, title: messageObj.title } }}>{messageObj.title}</NavLink>
{/* <NavLink replace to={`/home/messages/details/${messageObj.id}/${messageObj.title}`}>{messageObj.title}</NavLink> */}
{/* <NavLink replace to={`/home/messages/details?id=${messageObj.id}&title=${messageObj.title}`}>{messageObj.title}</NavLink> */}
<button onClick={()=>{this.pushShow(messageObj.id,messageObj.title)}}>push跳轉(zhuǎn)</button>
<button onClick={()=>{this.replaceShow(messageObj.id,messageObj.title)}}>replace跳轉(zhuǎn)</button>
</li>
)
})
}
</ul>
</div>
<Route path={'/home/messages/details'} component={Details} />
{/* <Route path={'/home/messages/details/:id/:title'} component={Details} /> */}
...
</div>
)
}
}
八堵未、withRouter的使用
我們知道腋舌,在路由組件中,我們可以使用props攜帶的參數(shù)來(lái)實(shí)現(xiàn)路由的跳轉(zhuǎn)以及參數(shù)的獲取渗蟹,那么對(duì)于非路由組件來(lái)說(shuō)块饺,如果想要路由組件的功能的話,可以怎么實(shí)現(xiàn)呢雌芽?
針對(duì)這個(gè)需求刨沦,react-router-dom
就提供了withRouter
這個(gè)函數(shù),幫助我們實(shí)現(xiàn)把一般組件包裝為路由組件膘怕。下面的Header組件原本是一個(gè)一般組件想诅,我們通過(guò)使用withRouter
函數(shù),把原先的Header組件作為參數(shù)傳入岛心,返回值就是一個(gè)包裝后的新組建
import React, { Component } from 'react';
import {withRouter} from 'react-router-dom'
class Header extends Component {
goForward = ()=>{
this.props.history.goForward();
}
goBack = ()=>{
this.props.history.goBack();
}
go = ()=>{
this.props.history.go(2);
}
render() {
return (
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
<button onClick={this.goForward}>前進(jìn)</button>
<button onClick={this.goBack}>后退</button>
<button onClick={this.go}>前進(jìn)+2</button>
</div>
)
}
}
export default withRouter(Header)
說(shuō)在最后
實(shí)際上来破,React路由中的內(nèi)容還是比較多的,本篇文章只是把常用的組件和函數(shù)進(jìn)行講解而已忘古,更多的使用方法還是要在實(shí)際項(xiàng)目中具體去查看文檔加以使用徘禁。
文章中用到案例已經(jīng)放在了碼云上,有需要的可以自行下載:https://gitee.com/moutory/react-staging