react-router使用教程

安裝命令

npm install -S react-router

基本用法

使用時,路由器Router就是React的一個組件,Router組件自己只是個容器,真正的路由要經過Route組件定義html

import React from 'react';
import ReactDOM from 'react-dom';
import {Router,Route,hashHistory} from 'react-router';

import App from './App.jsx';
import About from './About.jsx';

ReactDOM.render(
	<Router history={hashHistory}>
		<Route path="/" component={App}/>
		<Route path="/about" component={About}/>
	</Router>
, document.getElementById('app'))

路由模式

Router組件的history屬性,用來監聽瀏覽器地址欄的變化,並將URL解析成一個地址對象,供React Router匹配,history一個能夠設置三個值react

  • browserHistory
  • hashHistory
  • createMemoryHistory

若是設爲browserHistory,瀏覽器顯示的路徑是 example.com/some/path,背後調用的是瀏覽器的Histtory API.webpack

注意:使用browserHistory時須要對服務器改造,不然用戶直接向服務器請求某個子路由,會顯示找不到網頁404錯誤,若是開發服務器是webpack-dev-server 加上--history-api-fallback參數就能夠了,以下在package.json中,其餘服務器的配置請參考 https://github.com/ReactTraining/react-router/blob/master/docs/guides/Histories.md#configuring-your-servergit

"scripts": {
    "dev": "webpack-dev-server --history-api-fallback --hot",
    "build": "webpack --progress --hide-modules"
 },

若是設爲hashHistory,路由將經過URL的hash部分#切換,URL的形式相似 example.com/#/some/pathgithub

createMemoryHistory 主要用於服務器渲染,它建立一個內存中的history對象,不與瀏覽器URL互動。web

const history = createMemoryHistory(location)

嵌套路由

Route組件還能夠嵌套npm

ReactDOM.render(
	<Router history={browserHistory}>
		<Route path="/"  component={Layout}>
			<Route path="/index" component={App}/>
			<Route path="/about" component={About}/>
		</Route>
	</Router>
, document.getElementById('app'))

上面代碼中,用戶訪問/index或/about時候會先加載Layout組件,而後在Layout組件內部加載App或Abot,爲此Layout組件須要加個 {this.props.children}json

import React from "react"

export default React.createClass({
	render(){
		return (
			<div>
			<ul>
				<li><Link to="index">Index</Link></li>
				<li><Link to="about">About</Link></li>
			</ul>
			{this.props.children}
			</div>
		)
	}
})

上面代碼中,{this.props.children} 表明子組件 子路由也能夠不寫在Router組件裏面,單獨傳入Router組件的routers屬性api

import React from 'react';
import ReactDOM from 'react-dom';
import {Router,Route,hashHistory,browserHistory,createMemoryHistory} from 'react-router';

import Layout from './Layout.jsx';
import App from './App.jsx';
import About from './About.jsx';

let routes = <Route component={Layout}>
	<Route path="/" component={App} />
	<Route path="/about" component={About} />
</Route>	

ReactDOM.render(
	<Router routes={routes} history={browserHistory}></Router>
, document.getElementById('app'))

path屬性

Route組件的path屬性指定路由的匹配規則,這個屬性是能夠省略,這樣的話,無論路徑是否匹配,老是會加載指定組件。瀏覽器

<Route path="home" component={Layout}>
	<Route path="index" component={App} />
	<Route path="about(/:name)" component={About} />
</Route>

上面的例子中當用戶訪問/home/about/map 的時候,會加載下面的組件

<Layout>
		<About />
	</Layout>

若是省略外層Route的path參數,寫成下面的樣子

<Route component={Layout}>
	<Route path="index" component={App} />
	<Route path="about/:name" component={About} />
</Route>

如今訪問/about/test的時候會加載下面的組件

<Layout>
	<About />
</Layout>

通配符

path屬性可使用通配符

<Route path="/hello/:name"> 匹配 /hello/michael 
<Route path="/hello(/:name)> 匹配 /hello | /hello/test
<Route path="/hello/*.*> 匹配 /hello/a.jpg
<Route path="/hello/*> 匹配 /hello/  | /hello/test
<Route path="/**/*.jpg> 匹配 /hello/a.jpg | /hello/path/to/a.jpg

通配符規則以下

  • :paramName 匹配URL的一個部分,知道遇到下一個/、?、#爲止,這個路徑參數能夠經過this.props.params.paramName取出
  • () 表示URL的這個部分是可選的
  • * 匹配任意字符,知道模式裏面的下一個字符爲止,匹配方式是非貪婪模式。
  • ** 匹配任意字符,知道下一個 /、?、# 爲止,匹配方式是貪婪模式。

path 屬性也可使用相對路徑(不以/開頭),匹配時就會相對於父組件的路徑,能夠參考上一節的例子。嵌套路由若是想擺脫這個規則,可使用絕對路由。 路由匹配規則是從上到下執行,一旦發現匹配,就再也不匹配其他的規則了

<Route path="/hello" component="Hello">
<Route path="/hello" component="About">

上面的代碼中,路徑/hello同時匹配兩個規則,第二個規則不會生效。 設置路徑參數時,須要特別當心這一點。

<Route>
	<Route path="/:userName/:id" component="Hello">
	<Route path="/about/me" component="About"> 
</Route>

上面的代碼中,用戶訪問 /about/me 的時候永遠不會觸發第二個路由規則,由於匹配到第一個規則時候就匹配上了,不會向下走了,所以 帶參數的路徑通常要寫在路由規則的底部。

此外,URL的查詢字符串 /foo?bar=baz ,能夠用 this.props.location.query.bar 獲取

IndexRoute 組件

IndexRoute組件是爲了解決默認狀況下根路由的子組件問題的

<Router history={hashHistory}>
	<Route path="/" component={Layout}>
		<IndexRoute component={Index} />
		<Route path="app" component={App} />
		<Route path="about(/:name)" component={About} />
	</Route>
</Router>

上面代碼中,訪問根路徑 / 會加載Index組件到Layout組件的this.props.children

注意:IndexRoute組件沒有路徑參數path

Redirect 組件

Redirect組件用於路由的跳轉,即用戶訪問一個路由,會自動跳轉到另外一個路由

<Route path="/" component={Layout}>
	<Redirect from="/foo" to="/404" />
	<Route path="404" component={U404} />
	<Route path="app" component={App} />
	<Route path="about(/:name)" component={About} />
</Route>

如今訪問/foo,就會自動跳轉到/404

IndexRedirect 組件

IndexRedirect 組件用於訪問根路由的時候,講用戶重定向到某個子路由

<Route path="/" component={Layout}>
	<IndexRedirect to="/404" />
	<Route path="404" component={U404} />
	<Route path="app" component={App} />
	<Route path="about(/:name)" component={About} />
</Route>

上面代碼中,用戶訪問根路徑時,將自動重定向到子路由中

Link

Link 組件用於取代<a>元素,生成一個連接,容許用戶點擊後跳轉到另外一個路由。它基本上就是<a>元素的React版本,能夠接收Router的狀態。

<ul>
	<li><Link to="/">Index</Link></li>
	<li><Link to="app">App</Link></li>
	<li><Link to="about/ggg">About</Link></li>
</ul>

若是但願當前的路由與其餘路由有不一樣樣式,這時可使用Link組件的activeStyle屬性

<li><Link to="app" activeStyle={{color:'red'}}>App</Link></li>
<li><Link to="about" activeStyle={{color:'red'}}>About</Link></li>

上面代碼中,當前頁面的連接會紅色顯示。

另外一種作法是,使用activeClassName 指定當前路由的Class.

<li><Link to="app" activeClassName="active">App</Link></li>
<li><Link to="about" activeClassName="active">About</Link></li>

上面代碼中,當前頁面的連接會紅色顯示。

Router組件以外,導航到路由頁面,可使用瀏覽器的History API,像下面這樣寫。

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

或者這樣

this.context.router.push('/some/path')

IndexLink

若是連接到根路由/,不要使用Link組件,而要使用IndexLink組件。

這是由於對於根路由來講,activeStyleactiveClassName會失效,或者說老是生效,由於/會匹配任何子路由,而IndexLink組件會使用路徑的精確匹配

<IndexLink to="/" activeStyle={{color:'red'}}>Index</IndexLink>

上面代碼中,根路由只會在精確匹配時,纔會變成紅色

另外一種方法是使用Link組件的 onlyActiveOnIndex屬性,也能達到一樣效果。

<Link to="/" activeStyle={{color:'red'}} onlyActiveOnIndex={true}>Index</Link>

實際上,IndexLink 就是對Link組件的onlyActiveOnIndex屬性的包裝

路由的鉤子

每一個路由都有Enter和Leave鉤子,用戶進入或離開該路由時觸發。

<Route path="/app" component={App} onEnter={beforeRouter} onLeave={afterRouter} />

上面的例子中,用戶進入/app的時候會觸發onEnter鉤子,用戶離開/app的時候會觸發onLeave鉤子,詳細例子請看下面

import React from 'react';
import ReactDOM from 'react-dom';
import {Router,Route,IndexRoute,hashHistory} from 'react-router';

import Layout from './Layout.jsx';
import App from './App.jsx';
import Index from './Index.jsx';
import About from './About.jsx';
import NotFound from './NotFound.jsx';

const beforeRouter = (nextState,replace)=>{
	console.log("beforeRouter",nextState,replace)
}

const afterRouter = (nextState,replace)=>{
	console.log("afterRouter",nextState,replace)
}

ReactDOM.render(
	<Router history={hashHistory}>
		<Route path="/" component={Layout}>
			<IndexRoute component={Index} />
			<Route path="app" component={App} onEnter={beforeRouter} onLeave={afterRouter} />
			<Route path="about(/:name)" component={About} />
			<Route path="*" component={NotFound} />
		</Route>
	</Router>
, document.getElementById('app'))

本文摘自阮一峯的博客

相關文章
相關標籤/搜索