(注:参考自官方英文文档V3.X版本)

react-router是伴随着react框架出现的路由系统,它也是公认的一种优秀的路由解决方案。在使用react-router时候,我们常常会使用其自带的路径跳转组件Link,通过<Link  to="path"></Link>实现跳转,这和传统的<a href="path"></a>何其相似!但它们到底有什么具体的区别呢?

对比<a>,Link组件避免了不必要的重渲染

A  -- 通过<a>标签实现页面跳转:(图中的例子将会在下面详细解答)


----->----->


B --通过<Link>组件实现页面跳转:


  ------>


react-router:只更新变化的部分从而减少DOM性能消耗

react的创新之处在于,它利用虚拟DOM的概念和diff算法实现了对页面的"按需更新",react-router很好地继承了这一点,譬如上图所示,导航组件和三个Tab组件(通过...,通过...,通过...)的重渲染是我们不希望看到的,因为无论跳转到页面一或是页面二,它只需要渲染一次就够了。<Link>组件帮助我们实现了这个愿望,反观<a>标签,每次跳转都重渲染了导航组件和Tab组件试想一下,在一个浩大的项目里,这多么可怕!我们的"渲染"做了许多"无用功",而且消耗了大量弥足珍贵的DOM性能!

react-router的使用

1用npm安装依赖:通过终端进入项目目录里,写入npm install react-router安装react-router;

2从react-router的包里导入自带的组件如Router,Route等,一个简单的路由组件是这样的:

import React from 'react';
import { Router, Route, browserHistory} from 'react-router'
ReactDOM.render(
    <Router history={browserHistory}>
              <Route path='/' component={App}>
                  <Route path='pageOne/:id' component={PageOne}/>
                  <Route path='pageTwo/:id' component={PageTwo} />
              </Route>
     </Router>,
  document.getElementById('root')
);

其中App和PageOne,PageTwo是已定义的react组件

react-router的两大组件--Router和Route

1.Router组件

Router组件是react-router的基础组件,它位于最外层,作用是使UI和URL保持同步,要实现这一点需要向Router组件写入history属性值,Router的history属性有两个值:browserHistory和hashHistory(注:这两个值也是从react-router包中导入的)

  • browserHistory和hashHistory的区别?

        更改路由的方式不同

     1.browserHistory 使用的是 HTML5 的 pushState API来修改浏览器的历史记录

     2.hashHistory 是通过改变地址后面的 hash(也就是URL中#后面的值) 来改变浏览器的历史记录。

        两种方式的特点

1.History API 提供了 pushState() 和 replaceState() 方法来增加或替换历史记录。

而 hash 没有相应的方法,所以browserHistory有替换历史记录的功能,hashHistory没有

2hashHistory实现简单,不需要做额外的服务端改造

2.Route组件

Route组件的Props对象中包含有path和component两个属性。根据当前URL和path属性的比对,Route组件配合其他的Route组件将包裹的子组件映射成完整的组件树

  •   path属性:URL的路径,且子Route的path将与父Route的path组合起来,例如:
<Route path='/' component={Father}>
    <Route path='son' component={Son}>
</Route>

包裹Son组件的Route和包裹Father的Route是父Route和子Route的关系,所以子Route对应的URL为'/'+'son'='/son'

  • path的路径匹配语法:

:paramName -->匹配一段位于 /? 或 # 之后的 URL

()-->匹配可选字段

* -->匹配任意字段

       <Route path="/hello/:name">         // 匹配 /hello/michael 和 /hello/ryan
       <Route path="/hello(/:name)">       // 匹配 /hello, /hello/michael 和 /hello/ryan
       <Route path="/files/*.*">           // 匹配 /files/hello.jpg 和 /file/path/to/hello.jpg
  • component属性:

当匹配到 URL 时,单个的组件会被渲染。它可以 被父 route 组件的 this.props.children 渲染。

  • Route组件将以下属性通过props注入component组件中

children属性:子Route所包裹的component

params属性:URL的动态字段

location:当前的location对象

router属性:一个对象,包含有与路由跳转有关的方法如push(url),repalce(url),go(n),goBack(),goForward()等等

(下文提及)

所以,Route包裹的组件可通过props.chidren,props.params的方式去引用这些属性

React-router的静态跳转和动态跳转

  • 静态跳转 --通过<Link>组件实现静态跳转(文章开头demo的代码)

import React from 'react';
import { Router, Route, browserHistory,Link} from 'react-router'
import ReactDOM from 'react-dom'; class App extends React.Component{ render(){ return (<div> <h1>导航</h1> <a href='/pageOne/:id'>通过a标签跳转到页面一</a> <br/> <Link to='/pageOne/:id'>通过Link组件跳转到页面一</Link> <br/> <Link to='/pageTwo/:id'>通过Link组件跳转到页面二</Link> {this.props.children} </div>) } } const PageOne = (props) => { return (<div> <h1>页面一</h1> </div>) } const PageTwo = (props) => { return (<div> <h1>页面二</h1> </div>) } ReactDOM.render( <Router history={browserHistory}> <Route path='/' component={App}> <Route path='pageOne/:id' component={PageOne}/> <Route path='pageTwo/:id' component={PageTwo} /> </Route> </Router>, document.getElementById('root') )

demo:


-------->


  • 动态跳转 --通过Route注入component中的route属性实现动态跳转

上面我们通过Link组件实现了路径的跳转,但这种方式也有一定的局限性。

第一,它是静态的,也就是必须以写入组件的方式实现跳转;

第二,它没办法提供"时光旅行"的功能,比如:跳到历史记录中的前一个界面,后一个界面,前N个界面,后N个界面,

等等

那么,我们能不能通过调用一个方法的方式去动态地实现路径跳转呢?上文提到的从Route组件中传入component中的

router属性对象解决了这个问题:

  • router.push('url') -->跳到URL为url的页面
  • router.goBack()   -->返回上一个页面
  • router.goForward() --> 去往历史记录中的下一个页面
  • router.go(n): -->n为正数表示向前跳跃,n为负数表示向后跳跃

下面我们基于第一个例子实现这样一个功能,当在从导航跳转到页面一的时候,通过点击按钮调用函数router.push('/')跳回初始的导航页面

import React from 'react';
import { Router, Route, browserHistory,Link} from 'react-router'
import ReactDOM from 'react-dom';
class App extends React.Component{
  render(){
    return (<div>
              <h1>导航</h1>
              <a href='/pageOne/:id'>通过a标签跳转到页面一</a>
              <br/>
              <Link to='/pageOne/:id'>通过Link组件跳转到页面一</Link>
              <br/>
             <Link to='/pageTwo/:id'>通过Link组件跳转到页面二</Link>
              {this.props.children}
            </div>)
  }
}
const PageOne = (props) => {
  console.log(props.router)
  return (<div>
            <h1>页面一</h1>
            <button onClick={() => {
              props.router.push('/')
            }} style={{backgroundColor:'red'}}>
                 跳转到导航页面
            </button>
          </div>)
}
const PageTwo = (props) => {
  return (<div>
            <h1>页面二</h1>
          </div>)
}
ReactDOM.render(
           <Router history={browserHistory}>
              <Route path='/' component={App}>
                  <Route path='pageOne/:id' component={PageOne}/>
                  <Route path='pageTwo/:id' component={PageTwo} />
              </Route>
            </Router>,
document.getElementById('root')
       )

demo如下:


     ---->


React-router官方英文文档地址:

https://github.com/ReactTraining/react-router/tree/v3/docs

React-router官方中文文档地址:

https://react-guide.github.io/react-router-cn/index.html

(注意!英文为Version3版本,与暂处于Version2的中文文档有一定差别,注意区分)

【react-router】从Link组件和a标签的区别说起,react-router如何实现导航并优化DOM性能?的更多相关文章

  1. [React Router v4] Use the React Router v4 Link Component for Navigation Between Routes

    If you’ve created several Routes within your application, you will also want to be able to navigate ...

  2. React和Vue的组件更新比较

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px "Helvetica Neue"; color: #404040 } p. ...

  3. 翻译 | 玩转 React 表单 —— 受控组件详解

    原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 译者:小 B0Y 校对者:珂珂君 本文涵盖以下受控组件: 文本输入框 数字输 ...

  4. React中的通讯组件

    1.父传子:     传递:当子组件在父组件中当做标签使用的时候,给当前子组件绑定一个自定义属性,值为需要传递的数据     接收:在子组件内部通过this.props进行接收 2.子传父     传 ...

  5. reactjs-swiper react轮播图组件基于swiper

    react轮播图组件基于swiper demo地址:http://reactjs-ui.github.io/reactjs-swiper/simple.html 1. 下载安装 npm install ...

  6. 我们一起来详细的了解react的语法以及组件的使用方法

    jsx的介绍 React 使用 JSX 来替代常规的 JavaScript. JSX 是一个看起来很像 XML 的 JavaScript 语法扩展. jsx的优点 JSX 执行更快,因为它在编译为 J ...

  7. Vue之单文件组件的数据传递,axios请求数据及路由router

    1.传递数据 例如,我们希望把父组件的数据传递给子组件. 可以通过props属性来进行传递. 传递数据三个步骤: 步骤1:在父组件中,调用子组件的组名处,使用属性值的方式往下传递数据 <Menu ...

  8. React Native 学习-组件说明和生命周期

    组件的详细说明(Component Specifications) 当通过调用 React.createClass() 来创建组件的时候,你应该提供一个包含 render 方法的对象,并且也可以包含其 ...

  9. React:快速上手(2)——组件通信

    React:快速上手(2)——组件通信 向父组件传递数据 父组件可以通过设置子组件的props属性进行向子组件传值,同时也可以传递一个回调函数,来获取到子组件内部的数据. 效果演示 子组件是输入框,父 ...

随机推荐

  1. 【Ionic+AngularJS 开发】之『个人日常管理』App(二)

    准备工作 资源 预装工具 安装bower npm install -g bower 安装ngCordova bower install ngCordova (*由于网络获取资源的原因,后面几次建项目后 ...

  2. 关于小程序swiper不显示图的那些事

    还有几天快过年了,在这里提前祝大家新年快乐! 今天没事研究了一下小程序,想整个轮播图玩玩,然后开始看看文档https://mp.weixin.qq.com/debug/wxadoc/dev/compo ...

  3. mybatis关联查询,查询结果多条,却只返回一条记录

    原因是:主表和子表的主键字段相同,可以使用别名!这是因为mybatis的内部实现机制决定的: MyBatis为了降低内存开销,采用ResultHandler逐行读取的JDBC ResultSet结果集 ...

  4. Linux驱动技术(七) _内核定时器与延迟工作

    内核定时器 软件上的定时器最终要依靠硬件时钟来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行.实际上,时钟中断处理程 ...

  5. iOS企业版APP分发上线流程和注意事项

    0.准备 1]$299/year的企业级开发账号. 2]制作分发证书和描述文件,并下载安装到本机. 3]Xcode编译通过,真机测试通过的源码. 1.打包前配置 1]Xcode 打开项目,common ...

  6. JS高级程序设计学习笔记——继承

    我们知道,在OO语言中,继承可分为接口继承和实现继承.而ECMAScript的函数没有签名,不能实现“接口继承”,只能通过原型链实现“实现继承”. 在学习了各种继承模式之后,简单总结一下各种继承模式的 ...

  7. dns服务搭建

    DNS 是域名系统 (Domain Name System) 的缩写,它是由解析器和域名服务器组成的. 域名服务器是指保存有该网络中所有主机的域名和对应IP地址,并具有将域名转换为IP地址功能的服务器 ...

  8. Yii前台后台登录混淆问题

    我们在用yii开发项目时候,如果前后台使用modules实现 那么 做登录时候用户名就会出现前后台登录混淆的事情 于是可以在adminModule.php文件中做个设置 public function ...

  9. Selenium 运行时出现错误(java.lang.NoClassDefFoundError: com/google/common/base/Function)

    已经写好了java脚本,点击运行的过程中如果出现如下的错误提示时: java.lang.NoClassDefFoundError: com/google/common/base/Function 问题 ...

  10. C++ protected访问权限思考

    看了云风关于protected的思考,自己也总结了下. C++的访问权限有三个 private.protected.public. 如果不包括继承的话,比较好理解,可以分为类外和类内两部分.类外不能访 ...