React Router是一个路由库,通过管理URL来实现组件切换和状态转变。

1.安装和使用

  1. $ npm install -S react-router

在使用时,作为React组件导入

  1. import {Router} from 'react-router';
  2.  
  3. render(<Router />,document.getElementById('app'));

但是需要真正使用Router,还需要定义Router组件。

  1. import { Router, Route, hashHistory } from 'react-router';
  2.  
  3. render((
  4. <Router history={hashHistory}> //路由切换由URL的hash变化决定,即URL的#部分发生变化。举例来说,
  5. <Route path="/" component={App}/> //用户访问http://www.example.com/,实际会看到的是http://www.example.com/#/
  1. </Router> ), document.getElementById('app'));

在上述代码中,当用户访问根路由时,会自动加载App组件。

Route组件定义了URL路径和组件的对应关系,可同时使用多个Route组件

  1. <Router history = {hashHistory}>
  2. <route path = "/" component = {App} />
  3. <route path = "/name" component = {Name} />
  4. <route path = "/age" component = {Age} />
  5. </Router>

上面的代码中,当用户访问“http://www.xx.com/”时,加载App组件

当用户访问“http://www.xx.com/name”时,加载App组件和Name组件

当用户访问“http://www.xx.com/age”时,加载App组件和Age组件

2.嵌套路由

  

  1. <Router history={hashHistory}>
  2. <Route path="/" component={App}>
  3. <Route path="/name" component={Name}/>
  4. <Route path="/age" component={Age}/>
  5. </Route>
  6. </Router>

在上述代码中,如果用户访问‘http://www.xx.com/age’时,会首先加载App组件,然后在其内容加载Age组件。

  1. export default React.createClass({
  2. render(){
  3. return <div>
  4. this.props.children
  5. <div>
  6. }
  7. })

其中,this.props.children属性就是子组件。

子路由也可以不写在Router组件里面,单独传入Router组件的routes属性

  1. let routes = <Route path="/" component={App}>
  2. <Route path="/repos" component={Repos}/>
  3. <Route path="/about" component={About}/>
  4. </Route>;
  5.  
  6. <Router routes={routes} history={browserHistory}/>

3.path属性

Route组件的path属性指定路由的匹配规则。这个属性是可以省略的,这样的话,不管路径是否匹配,总是会加载指定组件,


  1. <Route path="inbox" component={Inbox}>
  2. <Route path="messages/:id" component={Message} />
  3. </Route>

上面代码中,当用户访问/inbox/messages/:id时,会加载下面的组件。


  1. <Inbox>
  2. <Message/>
  3. </Inbox>

如果省略外层Routepath参数,写成下面的样子。


  1. <Route component={Inbox}>
  2. <Route path="inbox/messages/:id" component={Message} />
  3. </Route>

现在用户访问/inbox/messages/:id时,组件加载还是原来的样子。


  1. <Inbox>
  2. <Message/>
  3. </Inbox>

四、通配符

  

  1. <Route path="/hello/:name">
  2. // 匹配 /hello/michael
  3. // 匹配 /hello/ryan
  4. <Route path="/hello(/:name)">
  5. // 匹配 /hello
  6. // 匹配 /hello/michael
  7. // 匹配 /hello/ryan
  8. <Route path="/files/*.*">
  9. // 匹配 /files/hello.jpg
  10. // 匹配 /files/hello.html
  11. <Route path="/files/*">
  12. // 匹配 /files/
  13. // 匹配 /files/a
  14. // 匹配 /files/a/b
  15. <Route path="/**/*.jpg">
  16. // 匹配 /files/hello.jpg
  17. // 匹配 /files/path/to/file.jpg
  18. 具体规则如下:

(1):paramName

:paramName匹配URL的一个部分,直到遇到下一个/?#为止。这个路径参数可以通过this.props.params.paramName取出。

(2)()

()表示URL的这个部分是可选的。

(3)*

*匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。

(4) **

** 匹配任意字符,直到下一个/?#为止。匹配方式是贪婪模式。

path属性也可以使用相对路径(不以/开头),匹配时就会相对于父组件的路径,可以参考上一节的例子。嵌套路由如果想摆脱这个规则,可以使用绝对路由。

路由匹配规则是从上到下执行,一旦发现匹配,就不再其余的规则了。


  1. <Route path="/comments" ... />
  2. <Route path="/comments" ... />

上面代码中,路径/comments同时匹配两个规则,第二个规则不会生效。

设置路径参数时,需要特别小心这一点。


  1. <Router>
  2. <Route path="/:userName/:id" component={UserPage}/>
  3. <Route path="/about/me" component={About}/>
  4. </Router>

上面代码中,用户访问/about/me时,不会触发第二个路由规则,因为它会匹配/:userName/:id这个规则。因此,带参数的路径一般要写在路由规则的底部。

此外,URL的查询字符串/foo?bar=baz,可以用this.props.location.query.bar获取。

五、IndexRoute 组件

下面的例子,你会不会觉得有一点问题?


  1. <Router>
  2. <Route path="/" component={App}>
  3. <Route path="accounts" component={Accounts}/>
  4. <Route path="statements" component={Statements}/>
  5. </Route>
  6. </Router>

上面代码中,访问根路径/,不会加载任何子组件。也就是说,App组件的this.props.children,这时是undefined

因此,通常会采用{this.props.children || <Home/>}这样的写法。这时,Home明明是AccountsStatements的同级组件,却没有写在Route中。

IndexRoute就是解决这个问题,显式指定Home是根路由的子组件,即指定默认情况下加载的子组件。你可以把IndexRoute想象成某个路径的index.html


  1. <Router>
  2. <Route path="/" component={App}>
  3. <IndexRoute component={Home}/>
  4. <Route path="accounts" component={Accounts}/>
  5. <Route path="statements" component={Statements}/>
  6. </Route>
  7. </Router>

现在,用户访问/的时候,加载的组件结构如下。


  1. <App>
  2. <Home/>
  3. </App>

这种组件结构就很清晰了:App只包含下级组件的共有元素,本身的展示内容则由Home组件定义。这样有利于代码分离,也有利于使用React Router提供的各种API。

注意,IndexRoute组件没有路径参数path

六、Redirect 组件

<Redirect>组件用于路由的跳转,即用户访问一个路由,会自动跳转到另一个路由。


  1. <Route path="inbox" component={Inbox}>
  2. {/* 从 /inbox/messages/:id 跳转到 /messages/:id */}
  3. <Redirect from="messages/:id" to="/messages/:id" />
  4. </Route>

现在访问/inbox/messages/5,会自动跳转到/messages/5

七、IndexRedirect 组件

IndexRedirect组件用于访问根路由的时候,将用户重定向到某个子组件。


  1. <Route path="/" component={App}>
  2. <IndexRedirect to="/welcome" />
  3. <Route path="welcome" component={Welcome} />
  4. <Route path="about" component={About} />
  5. </Route>

上面代码中,用户访问根路径时,将自动重定向到子组件welcome

八、Link

Link组件用于取代<a>元素,生成一个链接,允许用户点击后跳转到另一个路由。它基本上就是<a>元素的React 版本,可以接收Router的状态。


  1. render() {
  2. return <div>
  3. <ul role="nav">
  4. <li><Link to="/about">About</Link></li>
  5. <li><Link to="/repos">Repos</Link></li>
  6. </ul>
  7. </div>
  8. }

如果希望当前的路由与其他路由有不同样式,这时可以使用Link组件的activeStyle属性。


  1. <Link to="/about" activeStyle={{color: 'red'}}>About</Link>
  2. <Link to="/repos" activeStyle={{color: 'red'}}>Repos</Link>

上面代码中,当前页面的链接会红色显示。

另一种做法是,使用activeClassName指定当前路由的Class


  1. <Link to="/about" activeClassName="active">About</Link>
  2. <Link to="/repos" activeClassName="active">Repos</Link>

上面代码中,当前页面的链接的class会包含active

Router组件之外,导航到路由页面,可以使用浏览器的History API,像下面这样写。


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

九、IndexLink

如果链接到根路由/,不要使用Link组件,而要使用IndexLink组件。

这是因为对于根路由来说,activeStyleactiveClassName会失效,或者说总是生效,因为/会匹配任何子路由。而IndexLink组件会使用路径的精确匹配。


  1. <IndexLink to="/" activeClassName="active">
  2. Home
  3. </IndexLink>

上面代码中,根路由只会在精确匹配时,才具有activeClassName

另一种方法是使用Link组件的onlyActiveOnIndex属性,也能达到同样效果。


  1. <Link to="/" activeClassName="active" onlyActiveOnIndex={true}>
  2. Home
  3. </Link>

实际上,IndexLink就是对Link组件的onlyActiveOnIndex属性的包装。

十、histroy 属性

Router组件的history属性,用来监听浏览器地址栏的变化,并将URL解析成一个地址对象,供 React Router 匹配。

history属性,一共可以设置三种值。

  • browserHistory
  • hashHistory
  • createMemoryHistory

如果设为hashHistory,路由将通过URL的hash部分(#)切换,URL的形式类似example.com/#/some/path


  1. import { hashHistory } from 'react-router'
  2. render(
  3. <Router history={hashHistory} routes={routes} />,
  4. document.getElementById('app')
  5. )

如果设为browserHistory,浏览器的路由就不再通过Hash完成了,而显示正常的路径example.com/some/path,背后调用的是浏览器的History API。


  1. import { browserHistory } from 'react-router'
  2. render(
  3. <Router history={browserHistory} routes={routes} />,
  4. document.getElementById('app')
  5. )

但是,这种情况需要对服务器改造。否则用户直接向服务器请求某个子路由,会显示网页找不到的404错误。

如果开发服务器使用的是webpack-dev-server,加上--history-api-fallback参数就可以了。


  1. $ webpack-dev-server --inline --content-base . --history-api-fallback

createMemoryHistory主要用于服务器渲染。它创建一个内存中的history对象,不与浏览器URL互动。


  1. const history = createMemoryHistory(location)

十一、表单处理

Link组件用于正常的用户点击跳转,但是有时还需要表单跳转、点击按钮跳转等操作。这些情况怎么跟React Router对接呢?

下面是一个表单。


  1. <form onSubmit={this.handleSubmit}>
  2. <input type="text" placeholder="userName"/>
  3. <input type="text" placeholder="repo"/>
  4. <button type="submit">Go</button>
  5. </form>

第一种方法是使用browserHistory.push


  1. import { browserHistory } from 'react-router'
  2. // ...
  3. handleSubmit(event) {
  4. event.preventDefault()
  5. const userName = event.target.elements[0].value
  6. const repo = event.target.elements[1].value
  7. const path = `/repos/${userName}/${repo}`
  8. browserHistory.push(path)
  9. },

第二种方法是使用context对象。


  1. export default React.createClass({
  2. // ask for `router` from context
  3. contextTypes: {
  4. router: React.PropTypes.object
  5. },
  6. handleSubmit(event) {
  7. // ...
  8. this.context.router.push(path)
  9. },
  10. })

十二、路由的钩子

每个路由都有EnterLeave钩子,用户进入或离开该路由时触发。


  1. <Route path="about" component={About} />
  2. <Route path="inbox" component={Inbox}>
  3. <Redirect from="messages/:id" to="/messages/:id" />
  4. </Route>

上面的代码中,如果用户离开/messages/:id,进入/about时,会依次触发以下的钩子。

  • /messages/:idonLeave
  • /inboxonLeave
  • /aboutonEnter

下面是一个例子,使用onEnter钩子替代<Redirect>组件。


  1. <Route path="inbox" component={Inbox}>
  2. <Route
  3. path="messages/:id"
  4. onEnter={
  5. ({params}, replace) => replace(`/messages/${params.id}`)
  6. }
  7. />
  8. </Route>

onEnter钩子还可以用来做认证。


  1. const requireAuth = (nextState, replace) => {
  2. if (!auth.isAdmin()) {
  3. // Redirect to Home page if not an Admin
  4. replace({ pathname: '/' })
  5. }
  6. }
  7. export const AdminRoutes = () => {
  8. return (
  9. <Route path="/admin" component={Admin} onEnter={requireAuth} />
  10. )
  11. }

下面是一个高级应用,当用户离开一个路径的时候,跳出一个提示框,要求用户确认是否离开。


  1. const Home = withRouter(
  2. React.createClass({
  3. componentDidMount() {
  4. this.props.router.setRouteLeaveHook(
  5. this.props.route,
  6. this.routerWillLeave
  7. )
  8. },
  9. routerWillLeave(nextLocation) {
  10. // 返回 false 会继续停留当前页面,
  11. // 否则,返回一个字符串,会显示给用户,让其自己决定
  12. if (!this.state.isSaved)
  13. return '确认要离开?';
  14. },
  15. })
  16. )

上面代码中,setRouteLeaveHook方法为Leave钩子指定routerWillLeave函数。该方法如果返回false,将阻止路由的切换,否则就返回一个字符串,提示用户决定是否要切换。

  1.  

React Router学习笔记(转自阮一峰老师博客)的更多相关文章

  1. 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第一章

      鉴于最近用 vuejs 框架开发项目,其中有很多涉及到 es6 语法不太理解所以便认真地读了一下这本书. 地址:http://es6.ruanyifeng.com/#README 第一章:let ...

  2. makedown学习笔记(以后可能会用makedown写博客)

    学习手册 https://www.zybuluo.com/mdeditor?url=https%3A%2F%2Fwww.zybuluo.com%2Fstatic%2Feditor%2Fmd-help. ...

  3. Python学习笔记23:Django构建一个简单的博客网站(一个)

    在说如何下载和安装Django,本节将重点讨论如何使用Django站点. 一 新建project 命令:django-admin startproject mysite # 有的须要输入:django ...

  4. 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第二章

    第二章:变量的解构赋值 在es6 版本前,如果要为多个变量赋不同值,我想是件比较麻烦的事情.但es6 版本新推出了一个新技术那就是今天的主角变量的解构赋值. 变量解构赋值分为两种方法:数组解构赋值 和 ...

  5. express 阮一峰的博客

    http://javascript.ruanyifeng.com/nodejs/express.html next没怎么用过... 一个不进行任何操作.只传递request对象的中间件 functio ...

  6. 转: RSA原理 阮一峰的博客

    转:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html 讲的非常细致,易懂.

  7. DDOS 攻击的防范教程--转载自阮一峰的博客

    一个多月前,我的个人网站遭受 DDOS 攻击,下线了50多个小时.这篇文章就来谈谈,如何应对这种攻击. 需要说明的是,我对 DDOS 并不精通,从没想过自己会成为攻击目标.攻击发生以后,很多素昧平生的 ...

  8. react 入门教程 阮一峰老师真的是榜样

    -  转自阮一峰老师博客 React 入门实例教程   作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Nati ...

  9. React 入门学习笔记整理目录

    React 入门学习笔记整理(一)--搭建环境 React 入门学习笔记整理(二)-- JSX简介与语法 React 入门学习笔记整理(三)-- 组件 React 入门学习笔记整理(四)-- 事件 R ...

随机推荐

  1. RabbitMQ入门教程(六):路由选择Routing

    原文:RabbitMQ入门教程(六):路由选择Routing 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog. ...

  2. CSS 相对定位 绝对定位

    css中的相对定位和绝对定位. 定位标签:position 包含属性:relative(相对) absolute(绝对) 1.position:relative; 如果对一个元素进行相对定位,首先它将 ...

  3. Host xxx is not allowed to connect to this MariaDb server

    直接复制代码,无需修改 第一:// %:表示从任何主机连接到mysql服务器 GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' IDENTIFIED BY 'pass ...

  4. 利用ios safari浏览器生成桌面快捷方式并唤醒app的示例代码

    html 内容: //通过a链接唤醒app  <a href="app约定好的scheme" id="qbt" style="display:n ...

  5. 这样讲 SpringBoot 自动配置原理,你应该能明白了吧

    https://juejin.im/post/5ce5effb6fb9a07f0b039a14 前言 小伙伴们是否想起曾经被 SSM 整合支配的恐惧?相信很多小伙伴都是有过这样的经历的,一大堆配置问题 ...

  6. hadoop的三大组件安装

    安装过程分3步走: 1.安装namenode主机一台; 2.安装datanode主机三台; 3.启用集群的三大组件: HDFS,Mapreduce,Yarn. 重要的事情: 新建的虚拟机,预备安装ha ...

  7. linux误卸载openssl后的恢复

    一.原因 由于在编译mysql时,报ssl错误,于是想卸载openssl再重新安装 rpm -qa|grep openssl rpm -e openssl-.el7_6..x86_64 rpm -e ...

  8. ui自动化之selenium操作(三)xpath定位

    xpath 的定位方法,非常强大.使用这种方法几乎可以定位到页面上的任意元素. 1. 什么是xpath? xpath 是XML Path的简称, 由于HTML文档本身就是一个标准的XML页面,所以我们 ...

  9. GlobalLock锁定一个全局内存对象

    GlobalLock BAIPro

  10. centos安装mysql的正确方法

    1.官方安装文档 http://dev.mysql.com/doc/mysql-yum-repo-quick-guide/en/ 2.下载 Mysql yum包 http://dev.mysql.co ...