在這個(gè)教程里楷怒,我們會(huì)從一個(gè)例子React應(yīng)用開始學(xué)習(xí)react-router-dom蛋勺。其中你會(huì)學(xué)習(xí)如何使用Link
、NavLink
等來(lái)實(shí)現(xiàn)跳轉(zhuǎn)鸠删,Switch
和exact
實(shí)現(xiàn)排他路由和瀏覽器路徑歷史抱完。
也許學(xué)習(xí)react-router最好的辦法就是用react-router-dom v4來(lái)寫一個(gè)多頁(yè)的react應(yīng)用。這個(gè)react應(yīng)用會(huì)包含登錄刃泡、注冊(cè)巧娱、首頁(yè)碉怔、聯(lián)系人等頁(yè)面。但是禁添,首先讓我們來(lái)看一下react router v4的概念眨层,以及它與v3有什么不同的地方。
React router v4 vs v3
v4是react router的一次重寫上荡,所以和v3有很多不同的地方趴樱。主要有:
- 在react router v4里,路由不再是集中在一起的酪捡。它成了應(yīng)用布局叁征、UI的一部分。
- 瀏覽器用的router在
react-router-dom
里逛薇。所以捺疼,瀏覽器里使用的時(shí)候只需要importreact-router-dom
就可以。 - 新的概念
BrowerRouter
和HashRouter
永罚。他們各自服務(wù)于不同的情景下啤呼。詳見下文。 - 不在使用
{props.children}
來(lái)處理嵌套的路由呢袱。 - v4的路由默認(rèn)不再排他官扣,會(huì)有多個(gè)匹配。而v3是默認(rèn)排他的羞福,只會(huì)有一個(gè)匹配被使用惕蹄。
react-router-dom
是react-router中用于瀏覽器的。react-router
被分為一下幾部分:
- react-router是瀏覽器和原生應(yīng)用的通用部分治专。
- react-router-dom是用于瀏覽器的卖陵。
- react-router-native是用于原生應(yīng)用的。
React-router vs react-router-dom vs react-router-native
react-router
是核心部分张峰。react-router-dom
提供了瀏覽器使用需要的定制組件泪蔫。react-router-native
則專門提供了在原生移動(dòng)應(yīng)用中需要用到的部分。所以喘批,如果在本例中實(shí)現(xiàn)瀏覽器開發(fā)就只需要安裝react-router-dom
撩荣。
安裝
如上所說,我們使用react開發(fā)web應(yīng)用谤祖,所以只需要安裝react-router-dom
婿滓。
npm install react-router-dom --save
理解和使用react-router
-
BrowserRouter
老速,這是對(duì)Router
接口的實(shí)現(xiàn)粥喜。使得頁(yè)面和瀏覽器的history保持一致。如:window.location
橘券。 -
HashRouter
额湘,和上面的一樣卿吐,只是使用的是url的hash部分,比如:window.location.hash
锋华。 -
MemoryRouter
嗡官, -
NativeRouter
,處理react native內(nèi)的路由毯焕。 -
StaticRouter
衍腥,處理靜態(tài)路由,和v3一樣纳猫。
BrowserRouter vs HashRouter
在react-router的各種router中婆咸,<BrowserRouter>
和<HashRouter>
是可以在瀏覽器中使用的。如果你使用的是一個(gè)非靜態(tài)的站點(diǎn)芜辕、要處理各種不同的url那么你就需要使用BrowserRouter
尚骄。相反的如果你的server只處理靜態(tài)的url,那么就使用HashRouter
侵续。
理解和使用Route
<Route>組件是react router v4里最有用的組件倔丈。背后的使用哲學(xué)也很簡(jiǎn)單,無(wú)論何時(shí)你需要在匹配某個(gè)路徑的時(shí)候繪制一個(gè)組件状蜗,那么就可以使用Route
組件需五。
Route
組件可以使用如下的屬性:
- path屬性,字符串類型轧坎,它的值就是用來(lái)匹配url的警儒。
- component屬性,它的值是一個(gè)組件眶根。在
path
匹配成功之后會(huì)繪制這個(gè)組件蜀铲。 - exact屬性,這個(gè)屬性用來(lái)指明這個(gè)路由是不是排他的匹配属百。
- strict屬性记劝, 這個(gè)屬性指明路徑只匹配以斜線結(jié)尾的路徑。
還有其他的一些屬性族扰,可以用來(lái)代替component
屬性厌丑。
- render屬性,一個(gè)返回React組件的方法渔呵。傳說中的rencer-prop就是從這里來(lái)的怒竿。
- children屬性,返回一個(gè)React組件的方法扩氢。只不過這個(gè)總是會(huì)繪制耕驰,即使沒有匹配的路徑的時(shí)候。
多數(shù)的時(shí)候是用component
屬性就可以滿足录豺。但是朦肘,某些情況下你不得不使用render
或children
屬性饭弓。
- match
- location
- history
如:
使用組件:
<Route exact path="/" component={HomePage} />
使用render
屬性實(shí)現(xiàn)內(nèi)聯(lián)繪制:
<Route path="/" render={()=><div>HomePage</div>} />
來(lái)看哥更復(fù)雜的:
const FadingRoute = ({ component, ...rest }) => (
<Route {...rest} render={(props) => (
<FadeIn>
<componnet {...props} />
</FadeIn>
)} />
)
<FadingRoute path="/cool" component={Something} />
使用children
:
<ul>
<ListItemLink to="/somewhere" />
<LinkItemLink to="/somewhere-else" />
</ul>
const ListItemLink = ({to, ...rest}) => (
<Route path={to} children={({math}) => (
<li className={match ? 'active' : ''}>
<Link to={to} {...rest} />
</li>
)} />
)
更多關(guān)于react-router v4如何匹配路徑的內(nèi)容,請(qǐng)移步這里媒抠。
URL / Path / Route的參數(shù)
通常情況下弟断,我們都會(huì)在路徑里添加參數(shù)。這樣方便在不同的組件之間傳遞一些必要的數(shù)據(jù)趴生。那么我們?nèi)绾尾拍塬@取到這些傳遞的參數(shù)阀趴,并傳遞給組件中呢?我們只需要在路徑的最后加上/:param
苍匆。如:
<Route path="/:param1" component={HomePage} />
const HomePage = ({match}) => (
<div>
<h1> parameter => {match.params.param1}
</div>
);
一旦有路徑可以匹配成功舍咖,那么就會(huì)穿件一個(gè)擁有如下屬性的對(duì)象,并傳入繪制的組件里:
- url: 匹配的url锉桑。
- path:就是path排霉。
- isExact:如果
path
和當(dāng)前的widnow.location
的path部分完全相同的話。 - params:在URL里包含的參數(shù)民轴。
理解并使用Link
Link
是react router v4特有的一個(gè)組件攻柠。是用來(lái)代替上一版的anchor link。使用Link
可以在React應(yīng)用的不同頁(yè)面之間跳轉(zhuǎn)后裸。與unclor會(huì)重新加載整個(gè)頁(yè)面不同瑰钮,Link
只會(huì)重新加載頁(yè)面里和當(dāng)前url可以匹配的部分。
Link
組件需要用到to
屬性微驶,這個(gè)屬性的值就是react router要跳轉(zhuǎn)到的地址浪谴。如:
import { Link } from 'react-router-dom';
const Nav = () => (
<Link to '/'>Home</Link>
);
當(dāng)被點(diǎn)擊的時(shí)候,會(huì)跳轉(zhuǎn)到路徑:/
因苹。
to
屬性的值可以是一個(gè)字符串苟耻,也可以是一個(gè)location(pathname, hash, state和search)對(duì)象。比如:
<Link to{{
pathname: '/me',
search: '?sort=asc',
hash: '#hash',
state: { fromHome: true }
}} />
Link
也可以使用replace
屬性扶檐,如果點(diǎn)擊的話凶杖,那么history里的當(dāng)前領(lǐng)會(huì)被replace。
<Link>和<NavLink>
NavLink
是Link
的一個(gè)子類款筑,在Link組件的基礎(chǔ)上增加了繪制組件的樣式智蝠,比如:
<NavLink to="/me" activeStyle={{SomeStyle}} activeClassName="selected">
My Profile
</NavLink>
使用react router dom實(shí)現(xiàn)你的第一個(gè)demo
現(xiàn)在我們用react router dom來(lái)實(shí)現(xiàn)第一個(gè)demo。
首先奈梳,引入必要的組件杈湾。比如:Route
和BrowserRouter
。
import { BrowserRouter, Route } from 'react-router-dom';
接下來(lái)攘须,我們創(chuàng)建一些組件和一些Html標(biāo)簽漆撞。同時(shí)我們用react router v4里的Link
和NavLink
組件。
const BaseLayout = () => (
<div className="base">
<header>
<p>React Router v4 Browser Example</p>
<nav>
<ul>
<li><Link ="/">Home</Link></li>
<li><Link ="/about">About</Link></li>
<li><Link ="/me">Profile</Link></li>
<li><Link ="/login">Login</Link></li>
<li><Link ="/register">Register</Link></li>
<li><Link ="/contact">Contact</Link></li>
</ul>
</nav>
</header>
<div className="container">
<Route path="/" exact component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route path="/contact" component={ContactPage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Route path="/me" component={ProfilePage} />
</div>
<footer>
React Router v4 Browser Example (c) 2017
</footer>
</div>
);
然后我們來(lái)創(chuàng)建需要的組件:
const HomePage = () => <div>This is a Home Page</div>
const LoginPage = () => <div>This is a Login Page</div>
const RegisterPage = () => <div>This is a Register Page</div>
const ProfilePage = () => <div>This is a Profile Page</div>
const AboutPage = () => <div>This is a About Page</div>
const ContactPage = () => <div>This is a Contact Page</div>
最后,寫App
組件叫挟。
const App = () => (
<BrowserRouter>
<BaseLayout />
</BrowserRouter>
)
render(<App />, document.getElementById('root'));
如你所見艰匙,react router v4的組件還非常的易用的限煞。
理解和使用非排他的路由
在上例中抹恳,我們?cè)?code>HomePage組件的路由里使用了屬性exact
。
<Route path="/" exact component={HomePage} />
這是因?yàn)関4中的路由默認(rèn)都是非排他的署驻,這一點(diǎn)和v3的實(shí)現(xiàn)思路截然不同奋献。如果沒有exact
屬性,HomePage
組件和其他的組件就會(huì)同事繪制在頁(yè)面上旺上。
如瓶蚂,當(dāng)用戶點(diǎn)了登錄連接以后,"/"
和"/login"
都滿足匹配條件宣吱,對(duì)應(yīng)的登錄組件和Home組件就會(huì)同時(shí)出現(xiàn)在界面上窃这。但是,這不是我們期待的結(jié)果征候,所以我們要給"/"
path加上exact
屬性杭攻。
現(xiàn)在我們來(lái)看看非排他的路由有什么優(yōu)點(diǎn)。假如我們有一個(gè)子菜單組件需要顯示在profile頁(yè)面出現(xiàn)的時(shí)候也出現(xiàn)疤坝。我們可以簡(jiǎn)單的修改BasicLayout
來(lái)實(shí)現(xiàn)兆解。
const BaseLayout = () => (
<div className="base">
<header>
<p>React Router v4 Browser Example</p>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li>
<Link to="/me">Profile</Link>
<Route path="/me" component={ProfileMenu} />
</li>
{/*略*/}
</ul>
</nav>
</header>
</div>
);
這樣我們就會(huì)看到對(duì)應(yīng)于"/me"
路徑的組件都繪制出來(lái)了。這就是非排他路由的好處跑揉。
理解排他路由
排他路由是react router v3的默認(rèn)實(shí)現(xiàn)锅睛。只有第一個(gè)匹配的路由對(duì)應(yīng)的組件會(huì)被繪制。這一點(diǎn)也可以用react router v4的Switch
組件來(lái)實(shí)現(xiàn)历谍。在Switch
組件中现拒,只有第一個(gè)匹配的路由<Route>
或者<Redirect>
會(huì)被繪制:
import { Switch, Route } from 'react-router';
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route path="me" component={ProfilePage} />
<Route component={NotFound} />
</Switch>
瀏覽器歷史
react router v4中,提供了一個(gè)history
對(duì)象望侈。這個(gè)對(duì)象包含了多個(gè)api具练,可以用來(lái)操作瀏覽器歷史等。
你也可以在React應(yīng)用里使用history
對(duì)象的方法:
history.push("/my-path")
history.replace("/my-path")
用另外的方法可以寫成:
<Link to="/my-path" />
<Redirect to="my-path" />
使用<Redirect>組件實(shí)現(xiàn)重定向
無(wú)論何時(shí)你要重定向到另外一個(gè)地址的時(shí)候甜无,都可以使用Redirect
組件:
<Redirect to {{
pathname: '/register',
search: '?utm=something',
state: { referrer: someplage.com }
}}>
或者扛点,更為簡(jiǎn)單的:
<Redirect to="register" />
最后
react router v4讓開發(fā)react應(yīng)用變得更加的簡(jiǎn)單。讓react應(yīng)用內(nèi)的頁(yè)面跳轉(zhuǎn)更加簡(jiǎn)單岂丘。你只需要聲明一個(gè)BrowserRouter
或者HashRouter
陵究,然后在它的內(nèi)部放上一系列的Route
組件,這些主鍵只要包含path
和component
屬性奥帘。無(wú)論何時(shí)有了匹配的路由铜邮,那么它就會(huì)進(jìn)行非排他的繪制(所有匹配的路由都會(huì)繪制)。你也可以把Route
放在Switch
組件里來(lái)實(shí)現(xiàn)排他的繪制(只有第一個(gè)匹配的路由會(huì)被繪制)。你可以在路徑中傳遞參數(shù)松蒜,match
對(duì)象會(huì)保留這些參數(shù)扔茅。最后,所有在web中使用的路由組件都包含在react-router-dom
中秸苗。只需要引入react-router-dom
就可以使用召娜。