React Router学习笔记(转自阮一峰老师博客)
React Router是一个路由库,通过管理URL来实现组件切换和状态转变。
1.安装和使用
$ npm install -S react-router
在使用时,作为React组件导入
import {Router} from 'react-router'; render(<Router />,document.getElementById('app'));
但是需要真正使用Router,还需要定义Router组件。
import { Router, Route, hashHistory } from 'react-router'; render((
<Router history={hashHistory}> //路由切换由URL的hash变化决定,即URL的#
部分发生变化。举例来说,
<Route path="/" component={App}/> //用户访问http://www.example.com/
,实际会看到的是http://www.example.com/#/
</Router> ), document.getElementById('app'));
在上述代码中,当用户访问根路由时,会自动加载App组件。
Route组件定义了URL路径和组件的对应关系,可同时使用多个Route组件
<Router history = {hashHistory}>
<route path = "/" component = {App} />
<route path = "/name" component = {Name} />
<route path = "/age" component = {Age} />
</Router>
上面的代码中,当用户访问“http://www.xx.com/”时,加载App组件
当用户访问“http://www.xx.com/name”时,加载App组件和Name组件
当用户访问“http://www.xx.com/age”时,加载App组件和Age组件
2.嵌套路由
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="/name" component={Name}/>
<Route path="/age" component={Age}/>
</Route>
</Router>
在上述代码中,如果用户访问‘http://www.xx.com/age’时,会首先加载App组件,然后在其内容加载Age组件。
export default React.createClass({
render(){
return <div>
this.props.children
<div>
}
})
其中,this.props.children属性就是子组件。
子路由也可以不写在Router
组件里面,单独传入Router
组件的routes
属性
let routes = <Route path="/" component={App}>
<Route path="/repos" component={Repos}/>
<Route path="/about" component={About}/>
</Route>; <Router routes={routes} history={browserHistory}/>
3.path属性
Route
组件的path
属性指定路由的匹配规则。这个属性是可以省略的,这样的话,不管路径是否匹配,总是会加载指定组件,
<Route path="inbox" component={Inbox}>
<Route path="messages/:id" component={Message} />
</Route>
上面代码中,当用户访问/inbox/messages/:id
时,会加载下面的组件。
<Inbox>
<Message/>
</Inbox>
如果省略外层Route
的path
参数,写成下面的样子。
<Route component={Inbox}>
<Route path="inbox/messages/:id" component={Message} />
</Route>
现在用户访问/inbox/messages/:id
时,组件加载还是原来的样子。
<Inbox>
<Message/>
</Inbox>
四、通配符
<Route path="/hello/:name">
// 匹配 /hello/michael
// 匹配 /hello/ryan
<Route path="/hello(/:name)">
// 匹配 /hello
// 匹配 /hello/michael
// 匹配 /hello/ryan
<Route path="/files/*.*">
// 匹配 /files/hello.jpg
// 匹配 /files/hello.html
<Route path="/files/*">
// 匹配 /files/
// 匹配 /files/a
// 匹配 /files/a/b
<Route path="/**/*.jpg">
// 匹配 /files/hello.jpg
// 匹配 /files/path/to/file.jpg
具体规则如下:
(1):paramName
:paramName
匹配URL的一个部分,直到遇到下一个/
、?
、#
为止。这个路径参数可以通过this.props.params.paramName
取出。
(2)()
()
表示URL的这个部分是可选的。
(3)*
*
匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。
(4) **
**
匹配任意字符,直到下一个/
、?
、#
为止。匹配方式是贪婪模式。
path
属性也可以使用相对路径(不以/
开头),匹配时就会相对于父组件的路径,可以参考上一节的例子。嵌套路由如果想摆脱这个规则,可以使用绝对路由。
路由匹配规则是从上到下执行,一旦发现匹配,就不再其余的规则了。
<Route path="/comments" ... />
<Route path="/comments" ... />
上面代码中,路径/comments
同时匹配两个规则,第二个规则不会生效。
设置路径参数时,需要特别小心这一点。
<Router>
<Route path="/:userName/:id" component={UserPage}/>
<Route path="/about/me" component={About}/>
</Router>
上面代码中,用户访问/about/me
时,不会触发第二个路由规则,因为它会匹配/:userName/:id
这个规则。因此,带参数的路径一般要写在路由规则的底部。
此外,URL的查询字符串/foo?bar=baz
,可以用this.props.location.query.bar
获取。
五、IndexRoute 组件
下面的例子,你会不会觉得有一点问题?
<Router>
<Route path="/" component={App}>
<Route path="accounts" component={Accounts}/>
<Route path="statements" component={Statements}/>
</Route>
</Router>
上面代码中,访问根路径/
,不会加载任何子组件。也就是说,App
组件的this.props.children
,这时是undefined
。
因此,通常会采用{this.props.children || <Home/>}
这样的写法。这时,Home
明明是Accounts
和Statements
的同级组件,却没有写在Route
中。
IndexRoute
就是解决这个问题,显式指定Home
是根路由的子组件,即指定默认情况下加载的子组件。你可以把IndexRoute
想象成某个路径的index.html
。
<Router>
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="accounts" component={Accounts}/>
<Route path="statements" component={Statements}/>
</Route>
</Router>
现在,用户访问/
的时候,加载的组件结构如下。
<App>
<Home/>
</App>
这种组件结构就很清晰了:App
只包含下级组件的共有元素,本身的展示内容则由Home
组件定义。这样有利于代码分离,也有利于使用React Router提供的各种API。
注意,IndexRoute
组件没有路径参数path
。
六、Redirect 组件
<Redirect>
组件用于路由的跳转,即用户访问一个路由,会自动跳转到另一个路由。
<Route path="inbox" component={Inbox}>
{/* 从 /inbox/messages/:id 跳转到 /messages/:id */}
<Redirect from="messages/:id" to="/messages/:id" />
</Route>
现在访问/inbox/messages/5
,会自动跳转到/messages/5
。
七、IndexRedirect 组件
IndexRedirect
组件用于访问根路由的时候,将用户重定向到某个子组件。
<Route path="/" component={App}>
<IndexRedirect to="/welcome" />
<Route path="welcome" component={Welcome} />
<Route path="about" component={About} />
</Route>
上面代码中,用户访问根路径时,将自动重定向到子组件welcome
。
八、Link
Link
组件用于取代<a>
元素,生成一个链接,允许用户点击后跳转到另一个路由。它基本上就是<a>
元素的React 版本,可以接收Router
的状态。
render() {
return <div>
<ul role="nav">
<li><Link to="/about">About</Link></li>
<li><Link to="/repos">Repos</Link></li>
</ul>
</div>
}
如果希望当前的路由与其他路由有不同样式,这时可以使用Link
组件的activeStyle
属性。
<Link to="/about" activeStyle={{color: 'red'}}>About</Link>
<Link to="/repos" activeStyle={{color: 'red'}}>Repos</Link>
上面代码中,当前页面的链接会红色显示。
另一种做法是,使用activeClassName
指定当前路由的Class
。
<Link to="/about" activeClassName="active">About</Link>
<Link to="/repos" activeClassName="active">Repos</Link>
上面代码中,当前页面的链接的class
会包含active
。
在Router
组件之外,导航到路由页面,可以使用浏览器的History API,像下面这样写。
import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
九、IndexLink
如果链接到根路由/
,不要使用Link
组件,而要使用IndexLink
组件。
这是因为对于根路由来说,activeStyle
和activeClassName
会失效,或者说总是生效,因为/
会匹配任何子路由。而IndexLink
组件会使用路径的精确匹配。
<IndexLink to="/" activeClassName="active">
Home
</IndexLink>
上面代码中,根路由只会在精确匹配时,才具有activeClassName
。
另一种方法是使用Link
组件的onlyActiveOnIndex
属性,也能达到同样效果。
<Link to="/" activeClassName="active" onlyActiveOnIndex={true}>
Home
</Link>
实际上,IndexLink
就是对Link
组件的onlyActiveOnIndex
属性的包装。
十、histroy 属性
Router
组件的history
属性,用来监听浏览器地址栏的变化,并将URL解析成一个地址对象,供 React Router 匹配。
history
属性,一共可以设置三种值。
- browserHistory
- hashHistory
- createMemoryHistory
如果设为hashHistory
,路由将通过URL的hash部分(#
)切换,URL的形式类似example.com/#/some/path
。
import { hashHistory } from 'react-router' render(
<Router history={hashHistory} routes={routes} />,
document.getElementById('app')
)
如果设为browserHistory
,浏览器的路由就不再通过Hash
完成了,而显示正常的路径example.com/some/path
,背后调用的是浏览器的History API。
import { browserHistory } from 'react-router' render(
<Router history={browserHistory} routes={routes} />,
document.getElementById('app')
)
但是,这种情况需要对服务器改造。否则用户直接向服务器请求某个子路由,会显示网页找不到的404错误。
如果开发服务器使用的是webpack-dev-server
,加上--history-api-fallback
参数就可以了。
$ webpack-dev-server --inline --content-base . --history-api-fallback
createMemoryHistory
主要用于服务器渲染。它创建一个内存中的history
对象,不与浏览器URL互动。
const history = createMemoryHistory(location)
十一、表单处理
Link
组件用于正常的用户点击跳转,但是有时还需要表单跳转、点击按钮跳转等操作。这些情况怎么跟React Router对接呢?
下面是一个表单。
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="userName"/>
<input type="text" placeholder="repo"/>
<button type="submit">Go</button>
</form>
第一种方法是使用browserHistory.push
import { browserHistory } from 'react-router' // ...
handleSubmit(event) {
event.preventDefault()
const userName = event.target.elements[0].value
const repo = event.target.elements[1].value
const path = `/repos/${userName}/${repo}`
browserHistory.push(path)
},
第二种方法是使用context
对象。
export default React.createClass({ // ask for `router` from context
contextTypes: {
router: React.PropTypes.object
}, handleSubmit(event) {
// ...
this.context.router.push(path)
},
})
十二、路由的钩子
每个路由都有Enter
和Leave
钩子,用户进入或离开该路由时触发。
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
<Redirect from="messages/:id" to="/messages/:id" />
</Route>
上面的代码中,如果用户离开/messages/:id
,进入/about
时,会依次触发以下的钩子。
/messages/:id
的onLeave
/inbox
的onLeave
/about
的onEnter
下面是一个例子,使用onEnter
钩子替代<Redirect>
组件。
<Route path="inbox" component={Inbox}>
<Route
path="messages/:id"
onEnter={
({params}, replace) => replace(`/messages/${params.id}`)
}
/>
</Route>
onEnter
钩子还可以用来做认证。
const requireAuth = (nextState, replace) => {
if (!auth.isAdmin()) {
// Redirect to Home page if not an Admin
replace({ pathname: '/' })
}
}
export const AdminRoutes = () => {
return (
<Route path="/admin" component={Admin} onEnter={requireAuth} />
)
}
下面是一个高级应用,当用户离开一个路径的时候,跳出一个提示框,要求用户确认是否离开。
const Home = withRouter(
React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(
this.props.route,
this.routerWillLeave
)
}, routerWillLeave(nextLocation) {
// 返回 false 会继续停留当前页面,
// 否则,返回一个字符串,会显示给用户,让其自己决定
if (!this.state.isSaved)
return '确认要离开?';
},
})
)
上面代码中,setRouteLeaveHook
方法为Leave
钩子指定routerWillLeave
函数。该方法如果返回false
,将阻止路由的切换,否则就返回一个字符串,提示用户决定是否要切换。
React Router学习笔记(转自阮一峰老师博客)的更多相关文章
- 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第一章
鉴于最近用 vuejs 框架开发项目,其中有很多涉及到 es6 语法不太理解所以便认真地读了一下这本书. 地址:http://es6.ruanyifeng.com/#README 第一章:let ...
- makedown学习笔记(以后可能会用makedown写博客)
学习手册 https://www.zybuluo.com/mdeditor?url=https%3A%2F%2Fwww.zybuluo.com%2Fstatic%2Feditor%2Fmd-help. ...
- Python学习笔记23:Django构建一个简单的博客网站(一个)
在说如何下载和安装Django,本节将重点讨论如何使用Django站点. 一 新建project 命令:django-admin startproject mysite # 有的须要输入:django ...
- 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第二章
第二章:变量的解构赋值 在es6 版本前,如果要为多个变量赋不同值,我想是件比较麻烦的事情.但es6 版本新推出了一个新技术那就是今天的主角变量的解构赋值. 变量解构赋值分为两种方法:数组解构赋值 和 ...
- express 阮一峰的博客
http://javascript.ruanyifeng.com/nodejs/express.html next没怎么用过... 一个不进行任何操作.只传递request对象的中间件 functio ...
- 转: RSA原理 阮一峰的博客
转:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html 讲的非常细致,易懂.
- DDOS 攻击的防范教程--转载自阮一峰的博客
一个多月前,我的个人网站遭受 DDOS 攻击,下线了50多个小时.这篇文章就来谈谈,如何应对这种攻击. 需要说明的是,我对 DDOS 并不精通,从没想过自己会成为攻击目标.攻击发生以后,很多素昧平生的 ...
- react 入门教程 阮一峰老师真的是榜样
- 转自阮一峰老师博客 React 入门实例教程 作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Nati ...
- React 入门学习笔记整理目录
React 入门学习笔记整理(一)--搭建环境 React 入门学习笔记整理(二)-- JSX简介与语法 React 入门学习笔记整理(三)-- 组件 React 入门学习笔记整理(四)-- 事件 R ...
随机推荐
- 关于echarts 重绘/图表切换/数据清空
容器id 为main var myChart=document.getElementById("main") myChart.removeAttribute("_echa ...
- mycat的wrapper.log日志中发现主从切换报错
可能是MySQL在某些情况下重启(密切关注重启现象,关注日志,找出原因),导致mycat切换主从.由于设置了单向主从,mycat将从库切换为主库,原来的主库宕机.后来重新更新dnindex.conf之 ...
- Java语言利用Google的Thumbnailator处理图片
导读:在Java中制作高质量的缩略图可能是一项相当困难的任务,或者图片质量高页面加载慢等等原因使需要对图片进行处理,但是又不想写太多的代码太麻烦去处理图片,那么就可以使用Thumbnailator—— ...
- python之堆排序算法代码
以下是个人写的堆排序代码,原理我就不解释了(简单来说就是先建立一个大顶堆,然后进行顶点和最后节点的互换,互换之后需要重新建堆,两两比对,具体的话可以参照其他的,不过代码还是会于注释的. #根据问题进行 ...
- 关于ftp无法链接的情况
首先查看ftp是否安装 systemctl status vsftpd 如果没有先安装 yum install vsftpd 然后启动 systemctl start vsftpd 如果有报错 Job ...
- tensorflow中张量_常量_变量_占位符
1.tensor 在tensorflow中,数据是被封装在tensor对象中的.tensor是张量的意思,即包含从0到任意维度的张量.常数是0维度的张量,向量是1维度的张量,矩阵是二维度的张量,以及还 ...
- 对所有的webview添加userAgent
在appdelegate中- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDicti ...
- git每次更新都需要输入账号密码,如何解决?
//如果https请求pull每次都需要输入账号密码,则 git config --global credential.helper store 那么,在下一次更新,需要输入账号密码,然后git就 ...
- linux下的命令和常见问题笔记
nginx的三大功能: 1.http服务 2.反向代理 3.负载均衡 2.当nginx重启报:[root@localhost logs]# service nginx reloadReloading ...
- SSH开发环境整合
第一步:Spring开发环境搭建 1.1: 添加配置文件和相应spring-3.2-core.Jar 核心包 配置文件 <?xml version="1.0" encodin ...