(一) react-router-dom 安裝
React Router被拆分成下面幾個包:
-
react-router
:React Router 核心 -
react-router-dom
用于 DOM 綁定的 React Router - (用于Web瀏覽器) -
react-router-redux
React Router 和 Redux 的集成 - (搭配redux) -
react-router-native
用于 React Native 的 React Router -(用于ReactNative) -
react-router-config
靜態路由配置的小助手
npm install react-router-dom --save
(二) 組件
(1) <BrowserRouter>
(1) <BrowserRouter> 簡介:
對于網頁項目,存在<BrowserRouter>與<HashRouter>兩種組件:
<BrowserRouter>組件:在服務區來管理動態請求時使用。
<HashRouter>組件:用于靜態網站。
通常,我們更傾向選擇 <BrowserRouter>
-
BrowserRouter
: 瀏覽器自帶的API,restful風格(需要后臺做相應的調整); -
HashRouter
: 使用hash方式進行路由; -
MemoryRouter
: 在內存中管理history,地址欄不會變化。在reactNative中使用。
(2) <BrowserRouter> 屬性:
-
basename
: string
作用:為所有位置添加一個基準URL
使用場景:假如你需要把頁面部署到服務器的二級目錄,你可以使用 basename 設置到此目錄。
<BrowserRouter basename="/calendar"/> // basename:string
<Link to="/today"/> 最終渲染為 renders <a href="/calendar/today">
-
keyLength
: number
作用:設置它里面路由的 location.key 的長度。默認是6。(key的作用:點擊同一個鏈接時,每次該路由下的 location.key都會改變,可以通過 key 的變化來刷新頁面。)
使用場景:按需設置。
<BrowserRouter keyLength={12}/>
(2) <Route>
(1) <Route> 組件簡介:
<Route> 自帶三個 render method 和三個 props 。
render methods 分別是:
<Route component>
<Route render>
<Route children>
每種 render method 都有不同的應用場景
同一個<Route> 只使用一種 render method ,大部分情況下你將使用 component 。
children方式渲染會不管地址欄是否匹配都渲染一些內容,在這里加動畫一時很常見的做法。
props 分別是:
match
location
history
( match, location, history 使用方法已在文章末尾補充 -2017/11/8 )
三種渲染方式都會得到三個屬性match、history、location;
所有的 render method 無一例外都將被傳入這些 props;
渲染組件時,route props跟著一起渲染;
<Route path="/user/:username" component={User}/>
const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}
-
exact: bool
如果為 true,path 為 '/one' 的路由將不能匹配 '/one/two',反之,亦然。
-
strict: bool
對路徑末尾斜杠的匹配。如果為 true。path 為 '/one/' 將不能匹配 '/one' 但可以匹配 '/one/two'。
- 如果要確保路由沒有末尾斜杠,那么 strict 和
exact 都必須同時為 true
<Route exact strict path="/one" component={About}/>
(3) <Link>
- to: 后面可以接字符串,也可以跟對象(對象可以是動態地添加搜索的信息);
to: string
作用:跳轉到指定路徑
使用場景:如果只是單純的跳轉就直接用字符串形式的路徑。
to: object
作用:攜帶參數跳轉到指定路徑
作用場景:比如你點擊的這個鏈接將要跳轉的頁面需要展示此鏈接對應的內容,又比如這是個支付跳轉,需要把商品的價格等信息傳遞過去。
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}}/>
- replace: bool
replace: 當設置為true時,點擊鏈接后將使用新地址替換掉訪問歷史記錄里面的原地址。
為 true 時,點擊鏈接后將使用新地址替換掉上一次訪問的地址,什么意思呢,比如:你依次訪問 '/one' '/two' '/three' ’/four' 這四個地址,如果回退,將依次回退至 '/three' '/two' '/one' ,這符合我們的預期,假如我們把鏈接 '/three' 中的 replace 設為 true 時。依次點擊 one two three four 然后再回退會發生什么呢?會依次退至 '/three' '/one'!
(4) <NavLink>
<NavLink>是<Link>的一個特定版本, 會在匹配上當前URL的時候會給已經渲染的元素添加樣式參數;
-
activeClassName: string
導航選中激活時候應用的樣式名,默認樣式名為 active - activeStyle: object
如果不想使用樣式名就直接寫style - isActive,添加額外邏輯判斷是否生效 (決定導航是否激活,或者在導航激活時候做點別的事情。不管怎樣,它不能決定對應頁面是否可以渲染。)
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
(5) <Switch>
- <Switch>會遍歷自身的子元素(即路由)并對第一個匹配當前路徑的元素進行渲染。
( 只渲染出第一個與當前訪問地址匹配的 <Route> 或 <Redirect> )
- <Switch> 對于轉場動畫也非常適用,因為被渲染的路由和前一個被渲染的路由處于同一個節點位置!
<Fade>
<Switch>
{/* 用了Switch 這里每次只匹配一個路由,所有只有一個節點。 */}
<Route/>
<Route/>
</Switch>
</Fade>
<Fade>
<Route/>
<Route/>
{/* 不用 Switch 這里可能就會匹配多個路由了,即便匹配不到,也會返回一個null,使動畫計算增加了一些麻煩。 */}
</Fade>
(6) <Redirect>
- <Redirect/>可以寫在<Route/>的render屬性里面,也可以跟<Route/>平級;
- to: string
重定向的 URL 字符串 - to: object
重定向的 location 對象 - push: bool
若為真,重定向操作將會把新地址加入到訪問歷史記錄里面,并且無法回退到前面的頁面。 - from: string
需要匹配的將要被重定向路徑。
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/users" component={Users}/>
<Redirect from="/accounts" to="/users"/> // 將/accounts重定向到/users
<Route component={NoMatch}/>
</Switch>
------------------------------------------------------------------
2018-1-23更
import React, { Component } from 'react';
import {Route, Redirect} from 'react-router-dom'; // 引入Redirect
import A from '../component/a.js';
import B from '../component/b.js';
class RouterOne extends Component {
render() {
return (
<div className="R">
<Route path="/a" component={ A }/>
<Route path="/b" render={() => <Redirect to="/a"/>}/> // 使用Redirect
</div>
);
}
}
export default RouterOne;
(7) <Prompt> 提示
當用戶離開當前頁面前做出一些提示。用在Link或者Route的地方都行
- message: string
當用戶離開當前頁面時,設置的提示信息。 - message: func
當用戶離開當前頁面時,設置的回掉函數,函數是有默認參數的。 - when: bool
通過設置一定條件要決定是否啟用 Prompt,屬性值為true時啟用防止轉換;
<Prompt message="確定要離開?" />
(8) React-router4 使用
import {
BrowserRouter as Router, // 或者是HashRouter、MemoryRouter
Route, // 這是基本的路由塊
Link, // 這是a標簽
Switch // 這是監聽空路由的
Redirect // 這是重定向
Prompt // 防止轉換
} from 'react-router-dom'
實例:
index.js入口文件
import React from 'react';
import ReactDOM from 'react-dom';
import RouterComp from './router/router.js';
import {
BrowserRouter
} from 'react-router-dom';
import CommentApp from './commentApp';
import './index.css'
ReactDOM.render(
(
<BrowserRouter>
<CommentApp>
<RouterComp /> // RouterComp 存放所有Route
</CommentApp>
</BrowserRouter>
),document.getElementById('root'))
------------------------------------------------------------------------------------------
router.js
import React, {Component} from 'react';
import {
Route, Redirect, Switch, Prompt
} from 'react-router-dom';
import CommentApp from '../commentApp';
import ArrayC from '../component/ArrayC/ArrayC';
import ObjectC from '../component/ObjectC/ObjectC';
import RedirectComponents from '../component/Redirect/redirect';
export default class RouterA extends Component {
render() {
return(
<div>
<Switch> // 匹配第一個匹配到的Route
<Route path="/array" component={ArrayC}/>
<Route path="/object" component={ObjectC}/>
<Redirect from="/redirectgo" to="/object"/> // 路由重定向
<Route path="/redirectgo" component={RedirectComponents}/>
</Switch>
<Prompt message="確定要離開?" /> // 跳轉前提示
</div>
)
}
}
------------------------------------------------------------------------------------------
commentApp.js
import React, {Component} from 'react'
import {Link, NavLink} from 'react-router-dom'
class CommentApp extends Component {
render() {
return (
<div className='wrapper'>
<NavLink to="/array" activeClassName="abc" className='context2'>
<div>
數組測試
</div>
</NavLink>
<Link to="/object">
<div className='context3'>
對象測試
</div>
</Link>
<Link to="/redirectgo">
<div className='context4'>
重定向測試
</div>
</Link>
<div className="ArrayC">
{this.props.children} // <RouterComp /> 組件加載的位置
</div>
</div>
)
}
}
export default CommentApp
(九) location
location 是指你當前的位置,將要去的位置,或是之前所在的位置
它看起來像這樣:
{
key: 'ac3df4', // not with HashHistory!
pathname: '/somewhere'
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
}
(1)路由器將在幾個地方為您提供一個 location 對象:
在 Route component 中
,以 this.props.location 獲取-
在 Route render 中
,以 ({location}) => () 方式獲取 -
在 Route children 中
,以 ({location}) => () 方式獲取 -
在 withRouter 中
,以 this.props.location 的方式獲取
(2) location 對象不會發生改變,因此可以在生命周期的回調函數中使用 location 對象來查看當前頁面的訪問地址是否發生改變。這種技巧在獲取遠程數據以及使用動畫時非常有用
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
// navigated!
}
}
(3) 您可以使用location代替字符串導航到各個位置:
<Link to={location} />
<NaviveLink to={location} />
<Redirect to={location />
history.push(location)
history.replace(location)
location
它看起來像這樣:
{
key: 'ac3df4', // not with HashHistory!
pathname: '/somewhere'
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
}
(十) match
(1)match 對象包含了 <Route path> 如何與 URL 匹配的信息,具有以下屬性:
-
params
: object 路徑參數,通過解析 URL 中的動態部分獲得鍵值對 -
isExact
: bool 為 true 時,整個 URL 都需要匹配 -
path
: string 用來匹配的路徑模式,用于創建嵌套的 <Route> -
url
: string URL 匹配的部分,用于嵌套的 <Link>
(2) 在以下情境中可以獲取 match 對象 ( 和location獲取方法一樣 )
在 Route component 中
,以 this.props.match獲取-
在 Route render 中
,以 ({match}) => () 方式獲取 -
在 Route children 中
,以 ({match}) => () 方式獲取 -
在 withRouter 中
,以 this.props.match的方式獲取 -
matchPath
的返回值
當一個 Route 沒有 path 時,它會匹配一切路徑。
(十一) history
在組件中使用this.props.history
包含了以下信息:
- length 保存的路由記錄條數
- action:push,pop,replace
- location :當前路由信息
- goBack
- goForward等
2017/11/12日更新
(十二) react-router4 實現按需加載
(1) 首先使用官方提供的 bundle 組件 (這個組件和你用webpack打包的bundle沒啥關系)
Bundle.js的主要功能就是接收一個組件異步加載的方法,并返回相應的react組件
這里要注意:
由于webpack2以上已經不支持import loader 了,所以下面的方法不用 bundle-loader插件
bundle.js
由于import是promise結構,所有在下面的load = XXXXXX部分也要用promise結構
import React, {Component} from 'react'
export default class Bundle extends Component {
constructor(props) {
super(props);
this.state = {
mod: null
};
}
componentWillMount() {
this.load(this.props)
}
componentWillReceiveProps(nextProps) {
if (nextProps.load !== this.props.load) {
this.load(nextProps)
}
}
/*
load = (props) => {
this.setState({
mod:null
})
props.load((mod) => {
this.setState({
mod:mod.default?mod.default:mod
})
})
}
*/
上面注釋這段需要修改為:
load(props) {
this.setState({
mod: null
});
//注意這里,使用Promise對象; mod.default導出默認
props.load().then((mod) => {
this.setState({
mod: mod.default ? mod.default : mod
});
});
}
render() {
return this.state.mod ? this.props.children(this.state.mod) : null;
}
}
- (2)
1.在router.js中引入官方提供的bundle.js組件
2.在Route組件的component中使用bundle.js
3.在<Bundle load={ () => import('........') }中采用import方法
import React, {Component} from 'react';
// import { Route, Redirect, Switch, Prompt } from 'react-router-dom';
import { Route, Switch } from 'react-router-dom';
import Bundle from '../bundle/bundle.js';
export default class RouterA extends Component {
render() {
return(
<div>
<Switch>
<Route
path="/array/go?name=123"
component={ () => <Bundle load={() => import('../component/ArrayC/ArrayC')}>{ C => <C />}</Bundle>}
/>
<Route
path="/object"
component={ () => <Bundle load={ () => import('../component/ObjectC/ObjectC')}>{ C => <C /> }</Bundle>}
/>
<Route
path="/redirectgo"
component={ () => <Bundle load={ () => import('../component/Redirect/redirect')}>{ C => <C /> }</Bundle>}
/>
<Route
path="/string"
component={ () => <Bundle load={ () => import('../component/string/strig.js')}>{ C => <C /> }</Bundle>}
/>
</Switch>
</div>
)
}
}
( 填坑 ) http://www.lxweimin.com/p/547aa7b92d8c
( 踩坑 ) http://www.lxweimin.com/p/d712a5030c13