前兩天在寫react項目的時候發如今路由上面走了不少的彎路。正所謂磨刀不誤砍柴工,仍是先系統地學習一下吧...html
BrowserRouter: 瀏覽器自帶的API,restful風格(須要後臺作相應的調整);react
HashRouter: 使用hash方式進行路由;webpack
MemoryRouter: 在內存中管理history,地址欄不會變化。在reactNative中使用。web
該標籤有三種渲染方式component、render、children(絕大多數狀況使用component組件就行了);segmentfault
三種渲染方式都會獲得三個屬性match、history、location;瀏覽器
渲染組件時,route props跟着一塊兒渲染;babel
children方式渲染會無論地址欄是否匹配都渲染一些內容,在這裏加動畫一時很常見的作法。restful
to: 後面能夠接字符串,也能夠跟對象(對象能夠是動態地添加搜索的信息);react-router
replace: 當設置爲true時,點擊連接後將使用新地址替換掉訪問歷史記錄裏面的原地址。app
<NavLink>是<Link>的一個特定版本, 會在匹配上當前URL的時候會給已經渲染的元素添加樣式參數;
activeClassName,當地址匹配時添加相應class;
activeStyle,當地址匹配時添加相應style;
exact,當地址徹底匹配時,才生效;
isActive,添加額外邏輯判斷是否生效。
when: when的屬性值爲true時啓用防止轉換;
message: 後面能夠跟簡單的提示語,也能夠跟函數,函數是有默認參數的。
<Redirect/>能夠寫在<Route/>的render屬性裏面,也能夠跟<Route/>平級;
to: 依舊是能夠跟字符串或對象;
push: 添加該屬性時,地址不會被覆蓋,而是添加一條新紀錄;
from: 重定向,與<Route/>平級時。
params: 經過解析URL中動態的部分得到的鍵值對;
isExact: 當爲true時,整個URL都須要匹配;
path: 在須要嵌套<Route/>的時候用到;
url: 在須要嵌套<Link/>的時候會用到;
獲取方式: 以this.props.match方式。
import { BrowserRouter as Router, // 或者是HashRouter、MemoryRouter Route, // 這是基本的路由塊 Link, // 這是a標籤 Switch // 這是監聽空路由的 Redirect // 這是重定向 Prompt // 防止轉換 } from 'react-router-dom'
利用組件內的Redirect標籤。
const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( fakeAuth.isAuthenticated ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: '/login', state: { from: props.location } }}/> ) )}/> )
在組件內部添加Prompt標籤來進行權限控制。
<Prompt when={isBlocking} message={location => ( `你真的要跳轉到 ${location.pathname}麼?` )} />
樣式分別定義:.example-enter、.example-enter.example-enter-active、.example-leave、.example-leave.example-leave-active。
實例
<ReactCSSTransitionGroup transitionName="fade" transitionEnterTimeout={300} transitionLeaveTimeout={300} > <!-- 這裏和使用 ReactCSSTransitionGroup 沒有區別,惟一須要注意的是要把你的地址(location)傳入「Route」裏使它能夠在動畫切換的時候匹配以前的地址。 --> <Route location={location} key={location.key} path="/:h/:s/:l" component={HSL} /> </ReactCSSTransitionGroup>
藉助bundle-loader
實現按需加載。
新建一個bundle.js文件:
import React, { Component } from 'react' export default class Bundle extends React.Component { state = { // short for "module" but that's a keyword in js, so "mod" 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({ // handle both es imports and cjs mod: mod.default ? mod.default : mod }) }) } render() { if (!this.state.mod) return false return this.props.children(this.state.mod) } }
在入口處使用按需加載:
// bundle模型用來異步加載組件 import Bundle from './bundle.js'; // 引入單個頁面(包括嵌套的子頁面) // 同步引入 import Index from './app/index.js'; // 異步引入 import ListContainer from 'bundle-loader?lazy&name=app-[name]!./app/list.js'; const List = () => ( <Bundle load={ListContainer}> {(List) => <List />} </Bundle> ) <HashRouter> <Router basename="/"> <div> <Route exact path="/" component={Index} /> <Route path="/list" component={List} /> </div> </Router> </HashRouter>
webpack.config.js文件配置:
output: { path: path.resolve(__dirname, './output'), filename: '[name].[chunkhash:8].bundle.js', chunkFilename: '[name]-[id].[chunkhash:8].bundle.js', },
import Loadable from 'react-loadable' import Loading from './my-loading-component' Loadable({ loader: () => import(`views/AsyncView`), // 若是沒有loading動畫,就返回null LoadingComponent: () => null, // 若是有loading動畫,則以下 loading: Loading })
webpack配置:
// 添加插件babel-plugin-import-inspector { "plugins": [ ["import-inspector", { "serverSideRequirePath": true, "webpackRequireWeakId": true, }] ] }