1 為什么需要使用react-router
當(dāng)你寫了很多react組件后,想要實(shí)現(xiàn)不同組件之間的切換和跳轉(zhuǎn)的時(shí)候,react-router就派上用場(chǎng)了概作。
2 使用react-router-dom還是react-router
兩者區(qū)別不大,一般只使用react-router-dom就能滿足我們的需要枣抱。
3 安裝方法
npm install --save react-router-dom
4 如何使用
使用前要先引入
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'//這里將BrowserRouter重命名為Router
使用舉例
先打開(kāi)本地服務(wù)器布疙,如果不懂怎么做蚊惯,請(qǐng)看我的另一篇文章http://www.reibang.com/p/d08db717a66f
<Router>
<div>
<ul>
<li><Link to="/">主頁(yè)</Link></li>
<li><Link to="/hot">熱門</Link></li>
<li><Link to="/zhuanlan">專欄</Link></li>
</ul>
<hr/>
<Route exact path="/" component={App}></Route>
<Route path="/hot" component={Hot} ></Route>
<Route path="/zhuanlan" component={Zhuanlan}></Route>
</div>
</Router>
<Router></Router>相當(dāng)于一個(gè)盒子,里面只能包含一個(gè)子元素灵临。
react-router4之后截型,<Router></Router>標(biāo)簽里面可以包含任何html標(biāo)簽和react組件。
然而并不是react-route的其他標(biāo)簽必須包在Router里面儒溉,比如只要通過(guò)import { Route, Link} from 'react-route-dom'引入宦焦,可以隨意單獨(dú)使用Route和Link標(biāo)簽。
<Link></Link>標(biāo)簽和<a></a>標(biāo)簽類似顿涣,點(diǎn)擊<Link></Link>標(biāo)簽中的元素可以實(shí)現(xiàn)組件跳轉(zhuǎn)波闹。跳轉(zhuǎn)到哪個(gè)組件要看path的值"/"代表根路徑,相當(dāng)于localhost:8080這個(gè)路徑园骆,我們發(fā)現(xiàn)有一個(gè)<Route></Route>的path屬性和這個(gè)Link標(biāo)簽的path值相同舔痪,當(dāng)用戶點(diǎn)擊Link標(biāo)簽時(shí),會(huì)觸發(fā)和它具有相同path值的Route的component渲染锌唾,并且瀏覽器的網(wǎng)址那里的url變成他們的path值代表的路徑锄码。
因此,我們可以理解晌涕,“路由”就是要實(shí)現(xiàn)url跳轉(zhuǎn)滋捶,注意不要和直接打開(kāi)html文件哪個(gè)本地文件路徑搞混了,這里改變的是網(wǎng)址URL余黎,就是你的path值重窟,前面加上localhost:8080。
那么問(wèn)題來(lái)了惧财,url和文件路徑的區(qū)別是什么巡扇?
我們以前練習(xí)的時(shí)候,打開(kāi)我們的index.html是手動(dòng)直接打開(kāi)的垮衷,它在瀏覽器中顯示的路徑就是以我們的電腦哪個(gè)磁盤開(kāi)始的資源路徑厅翔,就是這個(gè)文件在電腦中的位置。
url路徑不同于資源路徑搀突,我們的組件Hot的url路徑是localhost:8080/hot刀闷,這是我們自己定義的,和Hot組件在電腦中的位置無(wú)關(guān),反正只要我們?cè)?lt;Route></Route>中定義了這個(gè)component的path甸昏,那么這個(gè)組件的url就確定了顽分,不用管它在電腦中的位置,當(dāng)然施蜜,在當(dāng)前文件中必須先引入這個(gè)組件卒蘸,還是按電腦中的相對(duì)路徑來(lái)的。所以花墩,你理解資源路徑和url的區(qū)別了嗎婚夫?
5 history的理解
如果你用過(guò)老版本的react-router仲锄,你一定知道history蛀骇。history是用來(lái)兼容不同瀏覽器或者環(huán)境下的歷史記錄管理的评汰,當(dāng)我跳轉(zhuǎn)或者點(diǎn)擊瀏覽器的后退按鈕時(shí),history就必須記錄這些變化祠肥。
browserHistory h5的history兼容性不好武氓,需要后端支持,在渲染組件的時(shí)候轉(zhuǎn)成hashHistory仇箱。
<Router history={browserHistory} routes={routes} />,
這種情況需要對(duì)服務(wù)器改造县恕。否則用戶直接向服務(wù)器請(qǐng)求某個(gè)子路由,會(huì)顯示網(wǎng)頁(yè)找不到的404錯(cuò)誤剂桥。
browserHistory 模式下忠烛,URL 是指向真實(shí) URL 的資源路徑,當(dāng)通過(guò)真實(shí) URL 訪問(wèn)網(wǎng)站的時(shí)候(首頁(yè))权逗,這個(gè)時(shí)候可以正常加載我們的網(wǎng)站資源美尸,而用戶在非首頁(yè)下手動(dòng)刷新網(wǎng)頁(yè)時(shí),由于路徑是指向服務(wù)器的真實(shí)路徑斟薇,但該路徑下并沒(méi)有相關(guān)資源(因?yàn)閡rl路徑是path中設(shè)置的路徑师坎,并不是資源路徑),用戶訪問(wèn)的資源不存在堪滨,返回給用戶的是 404 錯(cuò)誤
官方推薦使用browserHistory
History API 提供了 pushState() 和 replaceState() 方法來(lái)增加或替換歷史記錄胯陋。
而 hash 沒(méi)有相應(yīng)的方法,所以并沒(méi)有替換歷史記錄的功能袱箱。但 react-router 通過(guò) polyfill 實(shí)現(xiàn)了此功能遏乔,具體實(shí)現(xiàn)沒(méi)有看,好像是使用 sessionStorage发笔。
另一個(gè)原因是 hash 部分并不會(huì)被瀏覽器發(fā)送到服務(wù)端按灶,也就是說(shuō)不管是請(qǐng)求
http://domain.com/index.html#foo 還是http://domain.com/index.html#bar ,服務(wù)只知道請(qǐng)求了 index.html 并不知道 hash 部分的細(xì)節(jié)筐咧。而 History API 需要服務(wù)端支持,這樣服務(wù)端能獲取請(qǐng)求細(xì)節(jié)。
還有一個(gè)原因是因?yàn)橛行?yīng)用會(huì)忽略 URL 中的 hash 部分量蕊。
對(duì)于初學(xué)者铺罢,我推薦先使用<Router history={hashHistory}>,并且在引入Router時(shí)使用HashHistory as Router代替BrowserHistory as Router,以免出現(xiàn)不必要的麻煩残炮。
6 react-router4路由嵌套
什么是路由嵌套
路由嵌套势就,顧名思義就是路由/URL路徑的嵌套苞冯,比如舅锄,若Hot組件的路由是localhost:8080/hot皇忿,如果我們想要得Hot組件添加一個(gè)子組件Girl鳍烁,每次我們渲染Girl的時(shí)候,Hot也會(huì)自動(dòng)和他一起渲染糊闽,那么可以這樣寫
//父組件中
<Router>
<div>
<Route exact path="/" component={App}></Route>
<Route path="/hot" component={Hot} ></Route>
<Route path="/zhuanlan" component={Zhuanlan}></Route>
</div>
</Router>
//子組件中
<Route path="/hot/girl" component={Girl} ></Route>
理解<Route></Route>
在react-router4中墓怀,將他看做一個(gè)類似于組件的東西傀履,你想在哪里渲染組件钓账,就把他寫在哪里
//入口組件app.js
<Router history={hashHistory}>
<div>
<Route exact path="/" component={PCIndex}></Route>
<Route path="/hf" component={HeaderAndFooter}></Route>
</div>
</Router>
//HeaderAndFooter組件
<div>
<PCHeader />
<Route path="/hf/paper" component={BodyPaper}></Route>
<Route path="/hf/people" component={BodyPeople}></Route>
<BodyFooter />
</div>
路由對(duì)應(yīng):
localhost:8080----渲染PCIndex組件
localhost:8080/hf----渲染HeaderAndFooter組件
localhost:8080/hf/paper----同時(shí)渲染BodyPaper和HeaderAndFooter組件組件,并且BodyPaper組件在PCHeader組件和BodyFooter組件的中間
localhost:8080/hf/people----同時(shí)渲染BodyPeople和HeaderAndFooter組件組件啦粹,并且BodyPeople組件在PCHeader組件和BodyFooter組件的中間
7 組件路由參數(shù)傳遞match和:id的理解
match參數(shù)的理解
通過(guò)Route路由的組件唠椭,可以拿到一個(gè)match參數(shù)贪嫂,這個(gè)參數(shù)是一個(gè)對(duì)象力崇,其中包含幾個(gè)數(shù)據(jù):
isExact:這個(gè)關(guān)鍵字表示是為作全等匹配亮靴,比如台猴,寫了exact饱狂,“/”只能匹配PCIndex組件休讳,而不寫那就問(wèn)題大了俊柔,在localhost:8080路徑下雏婶,還可以匹配到HeaderAndFooter組件留晚,并將其渲染。
params:path中包含的一些額外數(shù)據(jù)
path:Route組件path屬性的值
url:實(shí)際url的hash值
示例
const HeaderAndFooter = ({match}) => (//{match}要先引入
<div>
<PCHeader />
<Route path={`${match.url}/paper`} component={BodyPaper}></Route>
<Route path="/hf/people" component={BodyPeople}></Route>
<BodyFooter />
</div>
)
export default HeaderAndFooter;
${match.url}獲取到的路徑就是HeaderAndFooter的path路徑
這里用到了es6的模板字符串功能,兩個(gè)反單引號(hào)括起來(lái)的字符串参歹,里面可以放js語(yǔ)句犬庇,比如變量械筛,但需要將變量名寫在${}之中
模板字符串之中還能調(diào)用函數(shù)let msg = Hello, ${place}
;
:id的理解
:id其實(shí)是官網(wǎng)文檔中的一種寫法,你也可以任意寫這個(gè)參數(shù),它放在url中赤赊,也是用來(lái)傳遞參數(shù)的抛计。它不是要參與url路由吹截,react-router會(huì)通過(guò)props.params傳遞給組件波俄,id表示參數(shù)變量懦铺,id有實(shí)際值將替換掉 :id ,變?yōu)閷?shí)際參數(shù)冬念。
比如:
當(dāng)我們請(qǐng)求/home/123/app/456的時(shí)候急前, 路由就會(huì)匹配到/home/:userId/app/:appId
其中params就是指的上面的userId 和 appId
轉(zhuǎn)換成json就是{userId: 123, appId: 456}
利用這種參數(shù)傳值:
示例
<Route path="/hf/people" component={BodyPeople}></Route>
<Route path={`${match.url}/:id`} component={BodyPaper}></Route>
當(dāng)我們?cè)L問(wèn)localhost:8080/fh/people的時(shí)候,就會(huì)渲染BodyPeople組件据块,people也會(huì)替換了url中的:id另假,渲染BodyPaper組件边篮。
可以用Switch解決這個(gè)問(wèn)題凌受,Switch下每次只匹配一個(gè)路由思杯,并且將這種含參數(shù)的url往下寫也是一個(gè)很好的習(xí)慣誊册。
<Switch>
{/* 用了Switch 這里每次只匹配一個(gè)路由案怯,所有只有一個(gè)節(jié)點(diǎn)。 */}
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
綜合示例
//父組件中
const Hot=({match})=>(<div>
<h2>熱門</h2>
<Link to={`${match.url}/article`}>文章</Link>
<Link to={`${match.url}/qa`}>問(wèn)答</Link>
<Link to={`${match.url}/news`}>新聞</Link>
<hr/>
<Route path={`${match.url}/:type`} component={Content}></Route>
</div>)
//子組件中
const Content=({match})=>(
<div>
<h2>熱門子目錄</h2>
<p>{match.params.type}</p>
</div>
)
可以發(fā)現(xiàn)match.params.type輕松取到了url中的參數(shù)至会。