【react-router】从Link组件和a标签的区别说起,react-router如何实现导航并优化DOM性能?
(注:参考自官方英文文档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性能?的更多相关文章
- [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 ...
- React和Vue的组件更新比较
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px "Helvetica Neue"; color: #404040 } p. ...
- 翻译 | 玩转 React 表单 —— 受控组件详解
原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 译者:小 B0Y 校对者:珂珂君 本文涵盖以下受控组件: 文本输入框 数字输 ...
- React中的通讯组件
1.父传子: 传递:当子组件在父组件中当做标签使用的时候,给当前子组件绑定一个自定义属性,值为需要传递的数据 接收:在子组件内部通过this.props进行接收 2.子传父 传 ...
- reactjs-swiper react轮播图组件基于swiper
react轮播图组件基于swiper demo地址:http://reactjs-ui.github.io/reactjs-swiper/simple.html 1. 下载安装 npm install ...
- 我们一起来详细的了解react的语法以及组件的使用方法
jsx的介绍 React 使用 JSX 来替代常规的 JavaScript. JSX 是一个看起来很像 XML 的 JavaScript 语法扩展. jsx的优点 JSX 执行更快,因为它在编译为 J ...
- Vue之单文件组件的数据传递,axios请求数据及路由router
1.传递数据 例如,我们希望把父组件的数据传递给子组件. 可以通过props属性来进行传递. 传递数据三个步骤: 步骤1:在父组件中,调用子组件的组名处,使用属性值的方式往下传递数据 <Menu ...
- React Native 学习-组件说明和生命周期
组件的详细说明(Component Specifications) 当通过调用 React.createClass() 来创建组件的时候,你应该提供一个包含 render 方法的对象,并且也可以包含其 ...
- React:快速上手(2)——组件通信
React:快速上手(2)——组件通信 向父组件传递数据 父组件可以通过设置子组件的props属性进行向子组件传值,同时也可以传递一个回调函数,来获取到子组件内部的数据. 效果演示 子组件是输入框,父 ...
随机推荐
- ArcGIS Pro 简明教程(1)Pro简介
ArcGIS Pro 简明教程(1)Pro简介 ArcGIS Pro已经发布了相当的一段时间了,截至笔者写这系列文章的时候已经是1.3版本了,已经是相当完善的一个版本,基本上已经完成了原来ArcGIS ...
- [原创.数据可视化系列之十二]使用 nodejs通过async await建立同步数据抓取
做数据分析和可视化工作,最重要的一点就是数据抓取工作,之前使用Java和python都做过简单的数据抓取,感觉用的很不顺手. 后来用nodejs发现非常不错,通过js就可以进行数据抓取工作,类似jqu ...
- int装箱比较
看过Effctive-java 这本书的人多少都会记得,int类型的值,-128到127之间的数,会进行缓存. 所以在心间装箱对象 new Integer()的时候,如果在此范围则不会新建对象而是使用 ...
- java多线程四种实现模板
假设一个项目拥有三块独立代码块,需要执行,什么时候用多线程? 这些代码块某些时候需要同时运行,彼此独立,那么需要用到多线程操作更快... 这里把模板放在这里,需要用的时候寻找合适的来选用. 总体分为两 ...
- JS冒号的作用
JS中冒号的作用1.声明对象的成员2.switch语句分支3.三元表达式 1.声明对象的成员 var Book = { Name: '法', Price: 100, Discount : functi ...
- 怎么监控apache运行状态和页面统计
通过使用mod_status的模块来监控Apache web server的负载. 1. mod_status是什么? mod_status是一个apache模块,它帮助监控web server负载和 ...
- 一个Python小白5个小时爬虫经历
前言 最近业余在做一个基于.NET Core的搜索项目,奈何基层代码写好了,没有看起来很华丽的数据供测试.很巧的也是博客搜索,于是乎想到了博客园.C#也能做做页面数据抓取的,不过在博客园看到的大部分都 ...
- [Kafka] - Kafka基本概念介绍
Kafka官方介绍:Kafka是一个分布式的流处理平台(0.10.x版本),在kafka0.8.x版本的时候,kafka主要是作为一个分布式的.可分区的.具有副本数的日志服务系统(Kafka™ is ...
- Linux下ifort的安装记录
首先进入网址https://software.intel.com/en-us/qualify-for-free-software/student 下载Intel Parallel Studio XE ...
- GridControl 设置自带选中复选框及设置该列列头名称
2.设置该列标题,设置事件CustomDrawColumnHeader 效果图: