React Router教程
React項(xiàng)目的可用的路由庫是React-Router
,當(dāng)然這也是官方支持的槽奕。它也分為:
- react-router 核心組件
- react-router-dom 應(yīng)用于瀏覽器端的路由庫(單獨(dú)使用包含了react-router的核心部分)
- react-router-native 應(yīng)用于native端的路由
以下教程我們都以Web端為主做院,所以所有的教程內(nèi)容都是默認(rèn)關(guān)于react-router-dom的介紹逐沙。
進(jìn)行網(wǎng)站(將會運(yùn)行在瀏覽器環(huán)境中)構(gòu)建续膳,我們應(yīng)當(dāng)安裝react-router-dom
腔召。react-router-dom
暴露出react-router
中暴露的對象與方法,因此你只需要安裝并引用react-router-dom
即可搂抒。
官方文檔地址: https://reacttraining.com/react-router/web/guides/philosophy
Installation | 安裝
安裝:
yarn add react-router-dom
# 或者艇搀,不使用 yarn
npm install react-router-dom
路由的基本概念
現(xiàn)在的React Router版本中已不需要路由配置,現(xiàn)在一切皆組件求晶。
ReactRouter中提供了以下三大組件:
Router是所有路由組件共用的底層接口組件焰雕,它是路由規(guī)則制定的最外層的容器。
Route路由規(guī)則匹配芳杏,并顯示當(dāng)前的規(guī)則對應(yīng)的組件矩屁。
Link路由跳轉(zhuǎn)的組件
當(dāng)然每個組件下又會有幾種不同的子類組件實(shí)現(xiàn)。比如: Router組件就針對不同功能和平臺對應(yīng)用:<BrowserRouter>
瀏覽器的路由組件<HashRouter>
URL格式為Hash路由組件<MemoryRouter>
內(nèi)存路由組件<NativeRouter>
Native的路由組件-
<StaticRouter>
地址不改變的靜態(tài)路由組件
三大組件使用的關(guān)系:image如果說我們的應(yīng)用程序是一座小城的話爵赵,那么Route就是一座座帶有門牌號的建筑物吝秕,而Link就代表了到某個建筑物的路線。有了路線和目的地空幻,那么就缺一位老司機(jī)了烁峭,沒錯Router就是這個老司機(jī)。
第一個Demo
現(xiàn)在你可以復(fù)制任意的示例代碼,并粘貼到src/App.js
约郁。如下:
import React, { Component } from 'react';
import { HashRouter as Router, Link, Route } from 'react-router-dom';
import './App.css';
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const About = () => (
<div>
<h2>About</h2>
</div>
)
const Product = () => (
<div>
<h2>Product</h2>
</div>
)
class App extends Component {
render() {
return (
<Router>
<div className="App">
<Link to="/">Home</Link>
<Link to="/About">About</Link>
<Link to="/Product">Product</Link>
<hr/>
<Route path="/" exact component={Home}></Route>
<Route path="/about" component={About}></Route>
<Route path="/product" component={Product}></Route>
</div>
</Router>
);
}
}
export default App;
Router組件
BrowserRouter組件
BrowserRouter
主要使用在瀏覽器中缩挑,也就是WEB應(yīng)用中。它利用HTML5 的history API來同步URL和UI的變化鬓梅。當(dāng)我們點(diǎn)擊了程序中的一個鏈接之后,BrowserRouter
就會找出與這個URL
匹配的Route
供置,并將他們對應(yīng)的組件渲染出來。 BrowserRouter
是用來管理我們的組件的绽快,那么它當(dāng)然要被放在最頂級的位置芥丧,而我們的應(yīng)用程序的組件就作為它的一個子組件而存在。
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>,
document.body);
BrowserRouter
組件提供了四個屬性坊罢。
-
basename
: 字符串類型续担,路由器的默認(rèn)根路徑 -
forceRefresh
: 布爾類型,在導(dǎo)航的過程中整個頁面是否刷新 -
getUserConfirmation
: 函數(shù)類型艘绍,當(dāng)導(dǎo)航需要確認(rèn)時執(zhí)行的函數(shù)赤拒。默認(rèn)是:window.confirm
-
keyLength
: 數(shù)字類型location.key
的長度秫筏。默認(rèn)是 6
basename 屬性
當(dāng)前位置的基準(zhǔn) URL诱鞠。如果你的頁面部署在服務(wù)器的二級(子)目錄,你需要將 basename 設(shè)置到此子目錄这敬。正確的 URL 格式是前面有一個前導(dǎo)斜杠航夺,但不能有尾部斜杠。
例如:有時候我們的應(yīng)用只是整個系統(tǒng)中的一個模塊崔涂,應(yīng)用中的URL總是以 http://localhost/admin/ 開頭阳掐。這種情況下我們總不能每次定義Link和Route的時候都帶上admin吧?react-router已經(jīng)考慮到了這種情況冷蚂,所以為我們提供了一個basename屬性缭保。為BrowserRouter設(shè)置了basename之后,Link中就可以省略掉admin了蝙茶,而最后渲染出來的URL又會自動帶上admin艺骂。
<BrowserRouter basename="/admin"/>
...
<Link to="/home"/> // 被渲染為 <a href="/admin/home">
...
</BrowserRouter>
getUserConfirmation: func
當(dāng)導(dǎo)航需要確認(rèn)時執(zhí)行的函數(shù)。默認(rèn)使用 window.confirm
隆夯。
// 使用默認(rèn)的確認(rèn)函數(shù)
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation}/>
forceRefresh: bool
當(dāng)設(shè)置為 true
時钳恕,在導(dǎo)航的過程中整個頁面將會刷新。 只有當(dāng)瀏覽器不支持 HTML5 的 history API 時蹄衷,才設(shè)置為 true
忧额。
const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory}/>
keyLength: number
location.key
的長度。默認(rèn)是 6愧口。
<BrowserRouter keyLength={12}/>
children: node
渲染單一子組件(元素)睦番。
HashRouter
HashRouter
使用 URL 的 hash (例如:window.location.hash
) 來保持 UI 和 URL 的同步。
注意: 使用 hash 的方式記錄導(dǎo)航歷史不支持
location.key
和location.state
耍属。在以前的版本中托嚣,我們?yōu)檫@種行為提供了 shim大咱,但是仍有一些問題我們無法解。任何依賴此行為的代碼或插件都將無法正常使用注益。由于該技術(shù)僅用于支持傳統(tǒng)的瀏覽器碴巾,因此在用于瀏覽器時可以使用<BrowserHistory>
代替。
跟BrowserRouter
類似丑搔,它也有:basename
厦瓢、getUserConfirmation
、children
屬性啤月,而且是一樣的煮仇。
hashType: string
window.location.hash
使用的 hash 類型。有如下幾種:
-
"slash"
- 后面跟一個斜杠谎仲,例如#/
和#/sunshine/lollipops
-
"noslash"
- 后面沒有斜杠浙垫,例如#
和#sunshine/lollipops
-
"hashbang"
- Google 風(fēng)格的 "ajax crawlable",例如#!/
和#!/sunshine/lollipops
默認(rèn)為 "slash"
郑诺。
MemoryRouter
主要用在ReactNative這種非瀏覽器的環(huán)境中夹姥,因此直接將URL的history保存在了內(nèi)存中。 StaticRouter 主要用于服務(wù)端渲染辙诞。
Link組件
Link就像是一個個的路牌辙售,為我們指明組件的位置。Link使用聲明式的方式為應(yīng)用程序提供導(dǎo)航功能飞涂,定義的Link最終會被渲染成一個a標(biāo)簽旦部。Link使用to這個屬性來指明目標(biāo)組件的路徑,可以直接使用一個字符串较店,也可以傳入一個對象士八。
import { Link } from 'react-router-dom'
// 字符串參數(shù)
<Link to="/query">查詢</Link>
// 對象參數(shù)
<Link to={{
pathname: '/query',
search: '?key=name',
hash: '#hash',
state: { fromDashboard: true }
}}>查詢</Link>
屬性: to
需要跳轉(zhuǎn)到的路徑(pathname)或地址(location)。
屬性:replace: bool
當(dāng)設(shè)置為 true
時梁呈,點(diǎn)擊鏈接后將使用新地址替換掉訪問歷史記錄里面的原地址婚度。
當(dāng)設(shè)置為 false
時,點(diǎn)擊鏈接后將在原有訪問歷史記錄的基礎(chǔ)上添加一個新的紀(jì)錄捧杉。
默認(rèn)為 false
陕见。
<Link to="/courses" replace />
NavLink組件
NavLink是一個特殊版本的Link,可以使用activeClassName來設(shè)置Link被選中時被附加的class味抖,使用activeStyle來配置被選中時應(yīng)用的樣式评甜。此外,還有一個exact屬性,此屬性要求location完全匹配才會附加class和style仔涩。這里說的匹配是指地址欄中的URl和這個Link的to指定的location相匹配忍坷。
// 選中后被添加class selected
<NavLink to={'/'} exact activeClassName='selected'>Home</NavLink>
// 選中后被附加樣式 color:red
<NavLink to={'/gallery'} activeStyle={{color:red}}>Gallery</NavLink>
activeClassName
默認(rèn)值為active
屬性
- to 可以是字符串或者對象,同Link組件
- exact 布爾類型,完全匹配時才會被附件class和style
- activeStyle Object類型
- activeClassName 字符串類型
- strict: bool類型佩研,當(dāng)值為
true
時柑肴,在確定位置是否與當(dāng)前 URL 匹配時,將考慮位置pathname
后的斜線旬薯。
Route組件
Route應(yīng)該是react-route中最重要的組件了晰骑,它的作用是當(dāng)location與Route的path匹配時渲染Route中的Component。如果有多個Route匹配绊序,那么這些Route的Component都會被渲染硕舆。
與Link類似,Route也有一個exact屬性骤公,作用也是要求location與Route的path絕對匹配抚官。
// 當(dāng)location形如 http://location/時,Home就會被渲染阶捆。
// 因?yàn)?"/" 會匹配所有的URL凌节,所以這里設(shè)置一個exact來強(qiáng)制絕對匹配。
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
Route的三種渲染方式
- component: 這是最常用也最容易理解的方式洒试,給什么就渲染什么倍奢。
- render: render的類型是function,Route會渲染這個function的返回值儡司。因此它的作用就是附加一些額外的邏輯娱挨。
<Route path="/home" render={() => {
console.log('額外的邏輯');
return (<div>Home</div>);
}/>
- children: 這是最特殊的渲染方式余指。
一捕犬、它同render類似,是一個function。不同的地方在于它會被傳入一個match參數(shù)來告訴你這個Route的path和location匹配上沒有酵镜。
二碉碉、第二個特殊的地方在于,即使path沒有匹配上淮韭,我們也可以將它渲染出來垢粮。秘訣就在于前面一點(diǎn)提到的match參數(shù)。我們可以根據(jù)這個參數(shù)來決定在匹配的時候渲染什么靠粪,不匹配的時候又渲染什么蜡吧。
// 在匹配時,容器的calss是light占键,<Home />會被渲染
// 在不匹配時昔善,容器的calss是dark,<About />會被渲染
<Route path='/home' children={({ match }) => (
<div className={match ? 'light' : 'dark'}>
{match ? <Home/>:<About>}
</div>
)}/>
所有路由中指定的組件將被傳入以下三個 props 畔乙。
- match.
- location.
- history.
這里主要說下match.params.透過這個屬性君仆,我們可以拿到從location中解析出來的參數(shù)。當(dāng)然,如果想要接收參數(shù)返咱,我們的Route的path也要使用特殊的寫法钥庇。
如下示例,三個Link是一個文章列表中三個鏈接咖摹,分別指向三篇id不同的文章评姨。而Route用于渲染文章詳情頁。注意path='/p/:id' 萤晴,location中的對應(yīng)的段會被解析為id=1 這樣的鍵值参咙。最終這個鍵值會作為param的鍵值存在。Route中的組件可以使用this.props.match.params.id來獲取硫眯,示例中使用了結(jié)構(gòu)賦值蕴侧。
<Link to='/p/1' />
<Link to='/p/2' />
<Link to='/p/3' />
......
<Route path='/p/:id' render={(match)=<h3>當(dāng)前文章ID:{match.params.id}</h3>)} />
location
Location 是指你當(dāng)前的位置,下一步打算去的位置两入,或是你之前所在的位置净宵,形式大概就像這樣:
{
key: 'ac3df4', // 在使用 hashHistory 時,沒有 key
pathname: '/somewhere'
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
}
你使用以下幾種方式來獲取 location 對象:
- 在 Route component 中裹纳,以
this.props.location
的方式獲取择葡, - 在 Route render 中,以
({ location }) => ()
的方式獲取剃氧, - 在 Route children 中敏储,以
({ location }) => ()
的方式獲取, - 在 withRouter 中朋鞍,以
this.props.location
的方式獲取已添。
你也可以在 history.location
中獲取 location 對象,但是別那么寫滥酥,因?yàn)?history 是可變的更舞。更多信息請參見 history 文檔。
location 對象不會發(fā)生改變坎吻,因此你可以在生命周期的鉤子函數(shù)中使用 location 對象來查看當(dāng)前頁面的位置是否發(fā)生改變缆蝉,這種技巧在獲取遠(yuǎn)程數(shù)據(jù)以及使用動畫時非常有用。
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
// 已經(jīng)跳轉(zhuǎn)了瘦真!
}
}
通常情況下刊头,你只需要給一個字符串當(dāng)做 location ,但是诸尽,當(dāng)你需要添加一些 location 的狀態(tài)時原杂,你可以對象的形式使用 location 。并且當(dāng)你需要多個 UI 弦讽,而這些 UI 取決于歷史時污尉,例如彈出框(modal)膀哲,使用location 對象會有很大幫助。
// 通常你只需要這樣使用 location
<Link to="/somewhere"/>
// 但是你同樣可以這么用
const location = {
pathname: '/somewhere'
state: { fromDashboard: true }
}
<Link to={location}/>
<Redirect to={location}/>
history.push(location)
history.replace(location)
最后被碗,你可以把 location 傳入一下組件:
- [Route]
- [Switch]
這樣做可以讓組件不使用路由狀態(tài)(router state)中的真實(shí) location某宪,因?yàn)槲覀冇袝r候需要組件去渲染一個其他的 location 而不是本身所處的真實(shí) location,比如使用動畫或是等待跳轉(zhuǎn)時锐朴。
history
本文檔中的「history」以及「history
對象」請參照 history
包中的內(nèi)容兴喂。 History 是 React Router 的兩大重要依賴之一(除去 React 本身),在不同的 Javascript 環(huán)境中焚志,history
以多種形式實(shí)現(xiàn)了對于 session 歷史的管理衣迷。
我們會經(jīng)常使用以下術(shù)語:
- 「browser history」 - history 在 DOM 上的實(shí)現(xiàn),經(jīng)常使用于支持 HTML5 history API 的瀏覽器端酱酬。
- 「hash history」 - history 在 DOM 上的實(shí)現(xiàn)壶谒,經(jīng)常使用于舊版本瀏覽器端。
- 「memory history」 - 一種存儲于內(nèi)存的 history 實(shí)現(xiàn)膳沽,經(jīng)常用于測試或是非 DOM 環(huán)境(例如 React Native)汗菜。
history
對象通常會具有以下屬性和方法:
-
length
-( number 類型)指的是 history 堆棧的數(shù)量。 -
action
-( string 類型)指的是當(dāng)前的動作(action)挑社,例如PUSH
陨界,REPLACE
以及POP
。 -
location
-( object類型)是指當(dāng)前的位置(location)痛阻,location 會具有如下屬性:-
pathname
-( string 類型)URL路徑菌瘪。 -
search
-( string 類型)URL中的查詢字符串(query string)。 -
hash
-( string 類型)URL的 hash 分段阱当。 -
state
-( string 類型)是指 location 中的狀態(tài)俏扩,例如在push(path, state)
時,state會描述什么時候 location 被放置到堆棧中等信息斗这。這個 state 只會出現(xiàn)在 browser history 和 memory history 的環(huán)境里动猬。
-
-
push(path, [state])
-( function 類型)在 hisotry 堆棧頂加入一個新的條目。 -
replace(path, [state])
-( function 類型)替換在 history 堆棧中的當(dāng)前條目表箭。 -
go(n)
-( function 類型)將 history 對戰(zhàn)中的指針向前移動n
。 -
goBack()
-( function 類型)等同于go(-1)
钮莲。 -
goForward()
-( function 類型)等同于go(1)
免钻。 -
block(prompt)
-( function 類型)阻止跳轉(zhuǎn),(請參照 history 文檔)
match
match
對象包含了 <Route path>
如何與URL匹配的信息崔拥。match
對象包含以下屬性:
-
params
-( object 類型)即路徑參數(shù)极舔,通過解析URL中動態(tài)的部分獲得的鍵值對。 -
isExact
- 當(dāng)為true
時链瓦,整個URL都需要匹配拆魏。 -
path
-( string 類型)用來做匹配的路徑格式盯桦。在需要嵌套<Route>
的時候用到。 -
url
-( string 類型)URL匹配的部分渤刃,在需要嵌套<Link>
的時候會用到拥峦。
你可以在以下地方獲取 match
對象:
- 在 Route component 中,以
this.props.match
方式卖子。 - 在 Route render中略号,以
({ match }) => ()
方式。 - 在 Route children中洋闽,以
({ match }) => ()
方式
Redirect組件
當(dāng)這個組件被渲染是玄柠,location會被重寫為Redirect的to指定的新location。它的一個用途是登錄重定向诫舅,比如在用戶點(diǎn)了登錄并驗(yàn)證通過之后羽利,將頁面跳轉(zhuǎn)到個人主頁。
<Redirect to="/new"/>
Switch組件
渲染匹配地址(location)的第一個 <Route>
或者<Redirect>
這與只使用一堆<Route>
有什么不同刊懈?
<Switch>
的獨(dú)特之處是獨(dú)它僅僅渲染一個路由铐伴。相反地,每一個包含匹配地址(location)的<Route>
都會被渲染俏讹。思考下面的代碼:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
如果現(xiàn)在的URL是 /about
当宴,那么 <About>
, <User>
, 還有 <NoMatch>
都會被渲染,因?yàn)樗鼈兌寂c路徑(path)匹配泽疆。這種設(shè)計(jì)户矢,允許我們以多種方式將多個 <Route>
組合到我們的應(yīng)用程序中,例如側(cè)欄(sidebars)殉疼,面包屑(breadcrumbs)梯浪,bootstrap tabs等等。 然而瓢娜,偶爾我們只想選擇一個<Route>
來渲染挂洛。如果我們現(xiàn)在處于 /about
,我們也不希望匹配 /:user
(或者顯示我們的 "404" 頁面 )眠砾。以下是使用 Switch
的方法來實(shí)現(xiàn):
import { Switch, Route } from 'react-router'
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
現(xiàn)在虏劲,如果我們處于 /about
, <Switch>
將開始尋找匹配的 <Route>
。 <Route path="/about"/>
將被匹配褒颈, <Switch>
將停止尋找匹配并渲染<About>
柒巫。 同樣,如果我們處于 /michael
谷丸, <User>
將被渲染堡掏。
這對于過渡動畫也是起作用的,因?yàn)槠ヅ涞?<Route>
在與前一個相同的位置被渲染刨疼。
<Fade>
<Switch>
{/* there will only ever be one child here */}
{/* 這里只會有一個子節(jié)點(diǎn) */}
<Route/>
<Route/>
</Switch>
</Fade>
<Fade>
<Route/>
<Route/>
{/* there will always be two children here,
one might render null though, making transitions
a bit more cumbersome to work out */}
{/* 這里總是有兩個子節(jié)點(diǎn),
一個可能會渲染為null, 使計(jì)算過渡增加了一點(diǎn)麻煩 */}
</Fade>
路由配置
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
// Some folks find value in a centralized route config.
// A route config is just data. React is great at mapping
// data into components, and <Route> is a component.
////////////////////////////////////////////////////////////
// first our route components
const Main = () => <h2>Main</h2>;
const Sandwiches = () => <h2>Sandwiches</h2>;
const Tacos = ({ routes }) => (
<div>
<h2>Tacos</h2>
<ul>
<li>
<Link to="/tacos/bus">Bus</Link>
</li>
<li>
<Link to="/tacos/cart">Cart</Link>
</li>
</ul>
{routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />)}
</div>
);
const Bus = () => <h3>Bus</h3>;
const Cart = () => <h3>Cart</h3>;
////////////////////////////////////////////////////////////
// then our route config
const routes = [
{
path: "/sandwiches",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos,
routes: [
{
path: "/tacos/bus",
component: Bus
},
{
path: "/tacos/cart",
component: Cart
}
]
}
];
// wrap <Route> and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = route => (
<Route
path={route.path}
render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes} />
)}
/>
);
const RouteConfigExample = () => (
<Router>
<div>
<ul>
<li>
<Link to="/tacos">Tacos</Link>
</li>
<li>
<Link to="/sandwiches">Sandwiches</Link>
</li>
</ul>
{routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />)}
</div>
</Router>
);
export default RouteConfigExample;
作者:CLYDE_6715
鏈接:http://www.reibang.com/p/6367cc1917e3
來源:簡書
簡書著作權(quán)歸作者所有泉唁,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處鹅龄。