React-Router 学习笔记
前言:
http://www.cnblogs.com/chenliyang/p/6547825.html
本文为个人学习react-router的总结。包括路由基础配置,跳转,权限管理,组件与路由配置的关系,代码分割。欢迎交流指导。
一、路由基础
1.路由配置 & 显示路由组件的view(类比angular的ui-view)
路由配置:路由匹配的规则
render(( <Router history={ hashHistory }> <Route path="/" component={ App }> <Route path="select" component={ Select }></Route> <Route path="found" component={ Found }></Route> <Route path="follow" component={ Follow }></Route> <Route path="my" component={ My }> <Route path=":myname" component={ MyName }></Route> <Route path="mysex" component={ MySex }></Route> </Route> </Route> </Router> ), document.getElementById('root'));
view:放置路由组件的地方(URL匹配了,然后对应的组件应该放到什么地方去),
每一个Route都只是一个组件,子路由就是 this.props.children 里面的组件,Route通过匹配URL决定显示哪一个子路由
class App extends PureComponent { render() { return ( <div> <GlobalNav /> { this.props.children } { /* this.props.children 是被嵌套在App的组件,相当于放子路由的View*/} </div> ) } }
二、默认路由(IndexRoute )
组件<App /> 的匹配路径是 ‘/', 有四个子路由,当前路由只是'/',那么<App />应该显示什么页面呢?
这里给与IndexRoute组件 -- 若希望直接使用4个其中一个则使用IndexRedirect
render(( <Router history={ hashHistory }> <Route path="/" component={ App }> <IndexRoute component={ IndexApp } /> <Route path="select" component={ Select }></Route> <Route path="found" component={ Found }></Route> <Route path="follow" component={ Follow }></Route> <Route path="my" component={ My }> <Route path=":myname" component={ MyName }></Route> <Route path="mysex" component={ MySex }></Route> </Route> </Route> </Router> ), document.getElementById('root'));
如果不使用IndexRoute组件,也还有一种投机取巧的方法,直接在 App组件中,使用 {this.props.children || <IndexApp />} ,在ui展示的层面上修改this.props.children为undefined的情况。
缺点:这种形式,没有参与到路由机制中,onEnter,onLeave 等HOOK都无法使用
三、路由跳转
1. IndexLink & Link (active状态之争)
倘若有如下两个链接,正好URL是'/my/mioawwwww', 两个路由都匹配的了,那么就是两个都是active状态(相应地添加activeStyle,activeClassName的样式)
<Link to="/my" >Mypage</Link> <Link to="/my/:myname" >myname</Link>
若你只想为 <Link to="/my/:myname" >myname</Link> 这一个按钮添加active样式,就可以为 <Link to="/my">Mypage</Link> 使用IndexLink
<IndexLink to="/my" >Mypage</IndexLink> <Link to="/my/:myname" >myname</Link>
IndexLink是补充Link的,只要URL完整匹配'/my'的时候才会激活active状态
2.跳转参数 to
2.1:通过 to=’xx/xx' 直接跳转 <Link to={`/my/${myname}/info`}>check my info</Link>
2.2:to=对象,带参数跳转(pathname, query, hash, state(额外数据)),注意:这些参数都被存放到this.props.location中
<li><Link to={{pathname:"/select", hash:'#ahash', query:{foo: 'bar', boo:'boz'}, state:{data:'miao'} }} activeClassName="GlobalNav-active">精选</Link></li>
2.3:to=函数,注册到路由跳转事件中,每一次路由变化,都会执行该函数,并经最新的location作为参数
<Link to={location => ({ ...location, query: { name: 'ryan' } })}> Hello </Link>
2.4:不使用Link,在函数内直接操作router
旧版本:由于router只用的context传递路由信息,因此每一个组件都可以轻易的通过this.context.router获取路由
新版本:router被放置在this.props中,通过this.props.router可以获取路由
注意:push与replace的区别,一个是添加,一个是替换,历史记录中被替换的已经不存在了,所以浏览器回退不到替换前的页面。
changeRouter = () => { console.log(this.props) // this.props.router.push('/follow'); // this.props.router.push({ // pathname:'/follow', // state:{name:'xxx'}, // query: {foo: 'bar'} // }) // this.props.router.replace('/follow'); this.props.router.replace({ pathname: '/follow', query: {foo:'bar'} }) }
3.若不是Route组件,而是Route的子组件,则this.props.router === undefined
若不使用Link,有两种方法
3.1 contextTypes
static contextTypes = { router: PropTypes.object } handleClick = (e) => { e.stopPropagation(); e.preventDefault(); this.context.router.push('login'); //...
3.2 引入browserHistory,hashHistory
import {browserHistory} from 'react-router'; //... handleClick = (e) => { e.stopPropagation(); e.preventDefault(); browserHistory.push('login') //...
四、重定向
<Redirect>:重定向到同等级的其他路由
<Redirect from="name/xxx" to='mysex' />
render(( <Router history={ browserHistory }> <Route path="/" component={ App }> <IndexRoute component={ IndexApp } /> <Route path="select" component={ Select }></Route> <Route path="found" component={ Found } onEnter={onEnterHook} onLeave={onLeaveHook}></Route> <Route path="follow" component={ Follow }> </Route> <Route path="my" component={ My } > <Redirect from="name/xxx" to='mysex' /> <Route path="name/:myname" component={ MyName }> <Route path="info" component={ MyInfo } ></Route> </Route> <Route path="mysex" component={ MySex } /> </Route> <Redirect from="*" to='/' /> </Route> </Router> ), document.getElementById('root'));
<IndexRedirect>:从父路由的目录开始重定向
<Route path="/" component={App}> <IndexRedirect to="/welcome" /> <Route path="welcome" component={Welcome} /> <Route path="about" component={About} /> </Route>
五、路由机制的权限
1.onEnter
const onEnterHook = (nextState, replace /*,cb*//*若添加cb参数,钩子变成异步执行,cb返回之前,将发生阻塞*/) => { console.log('onenter', nextState); // replace // 是router.replace(),若访问者没有权限,则引导到其他页面 }
nextState的属性
2.onLeave:与onEnter类似,nextState属性不同
3.onChange(prevState, nextState, replace, callback?) ,用于子路由,
进入该路由的某个子路由是触发,或者改变query,hash
一旦添加onChange属性,则子路由通过onChangeHook决定,Link不起作用
六、组件与路由的一一对应关系,按需加载组件
<Route path="follow" component={ Follow }></Route> // this.props.children; <Route path="follow" component={ {main:Follow, sidebar: Sidebar} }></Route> // const { main, sidebar } = this.props;
异步加载组件,使用(需要加上 require.ensure([], (require) => {}) 实现代码分割
getComponent(nextState, callback) && getComponents(nextState, callback)
cb(err, component)
getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('./components/Calendar')) }) }
七、每一个Route组件的属性
八、另一种路由配置的方式
const selectRouter = { path:'select', component: Select } const foundRouter = { path:'found', component: Found } const myRouter = { path:'my', getComponent(nextState,cb) { cb(null, My) } } // import Follow from './components/Follow.js'; const followRouter = { path:'follow', getComponent(nextState,cb) { require.ensure([], (require) => { cb(null, require('./components/Follow')) }) } // getComponent(nextState, cb) { // cb(null, Follow) // } } const rootRouter = { path: '/', component: App, // indexRoute: {component:IndexApp}, childRoutes: [ selectRouter, foundRouter, followRouter, // require('./components/Follow.index'), myRouter ] } // const rootRouter = { // path: '/', // component: App, // getIndexRoute(partialNextState, cb) { // cb(null, {compoment:IndexApp}); // }, // getChildRoutes(location, cb) { // cb(null, [ // selectRouter, // foundRouter, // followRouter, // myRouter // ]) // } // } render( <Router history={browserHistory} routes={rootRouter} />, document.getElementById('root') )
代码分割的注意事项:
1. require.ensure中分割的组件,需要使用module.export 暴露出来
module.exports = xxx; //可获取xxx组件 export default xxx // 不可获取xxx组件
2. getComponent,getComponents,getIndexRoute,getChildRoutes只是实现了异步加载,要实现代码分割还是要使用require.ensure
相关文章
- java学习笔记(四)面向对象
- 数据结构(逻辑结构,物理结构,特点) C#多线程编程的同步也线程安全 C#多线程编程笔记 String 与 StringBuilder (StringBuffer) 数据结构与算法-初体验(极客专栏)
- 第七节:语法总结(1)(自动属性、out参数、对象初始化器、var和dynamic等) 图片放大镜 JavaScript-基础 用javascript写原生ajax(笔记) 初遇 Asp.net MVC 数据库依赖缓存那些事儿 前端JS 与 后台C# 之间JSON序列化与反序列化(笔记)
- Nginx学习笔记(一) Nginx架构
- MicroPython内核开发笔记书内软件用例 :ADC 相关实验
- 机器学习笔记之集成学习(一)偏差与方差
- 机器学习笔记之变分推断(二)公式推导过程(基于平均场假设)
- 机器学习笔记之高斯分布(二)——基于参数预测的有偏估计与无偏估计
- 计算机网络学习笔记(1)概述
- 学习笔记——Linux的open、write、read、lseek、close函数
- Web 在线文件管理器学习笔记与总结(1)初始文件以及获取首层目录信息
- Android Bitmap和Canvas学习笔记
- 《react学习之道》---阅读笔记
- SQLite学习笔记之新手使用数据库最常犯的三个错误
- 小治同学的JAVAWEB学习笔记-Junit&反射&注解
- 学习笔记---Javascript事件Event、IE浏览器下的拖拽效果
- LwIP应用开发笔记之八:LwIP无操作系统HTTP客户端
- 深度学习入门笔记之PyTorch
- 【Java】Java学习笔记-控制语句
- 算法基础复盘笔记Day02【算法基础】—— 前缀和与差分、双指针算法、位运算、离散化、区间合并
- Oracle 学习笔记 18 -- 存储函数和存储过程(PL/SQL子程序)
- JVM学习笔记(一)------基本结构
- Mybatis学习笔记——day01
- C语言学习笔记——补充知识
- Spring学习笔记(一)---概念入门
- tensorflow中的神经网络笔记