React Router 是专为 React 设计的路由解决方案,在使用 React 来开发 SPA (单页应用)项目时,都会需要路由功能,而 React Router 应该是目前使用率最高的。

React Router 并不是 Facebook 的 React 官方团队开发的,但是据说有官方人员参与开发。React Router 的设计思想来源于 Ember 的路由,如果原来有用过 Ember 的路由,那么应该对 React Router 不会陌生。

什么是路由?

对于没有开发过后端,也没有开发过 SPA 的前端来说,「路由」这个名词可能会让人比较困惑,这里的路由并不是指「硬件路由」,也不是网络七层协议中的「网络层路由」,但是其思想原理是一样的。我尽量简单通俗的介绍一下。

假如我们有一台提供 Web 服务的服务器的网络地址是:10.0.0.1,而该 Web 服务又提供了三个可供用户访问的页面,其页面 URI 分别是:

 
http://10.0.0.1/
http://10.0.0.1/about
http://10.0.0.1/concat
 

那么其路径就分别是 //about/concat

当用户使用 http://10.0.0.1/about 来访问该页面时,Web 服务会接收到这个请求,然后会解析 URI 中的路径 /about,在 Web 服务的程序中,该路径对应着相应的处理逻辑,程序会把请求交给路径所对应的处理逻辑,这样就完成了一次「路由分发」,这个分发就是通过「路由」来完成的。

前端路由

前端的路由和后端的路由在实现技术上不一样,但是原理都是一样的。在 HTML5 的 history API 出现之前,前端的路由都是通过 hash 来实现的,hash 能兼容低版本的浏览器。如果我们把上面例子中提到的 3 个页面用 hash 来实现的话,它的 URI 规则中需要带上 #

http://10.0.0.1/
http://10.0.0.1/#/about
http://10.0.0.1/#/concat
 

Web 服务并不会解析 hash,也就是说 # 后的内容 Web 服务都会自动忽略,但是 JavaScript 是可以通过 window.location.hash 读取到的,读取到路径加以解析之后就可以响应不同路径的逻辑处理。

history 是 HTML5 才有的新 API,可以用来操作浏览器的 session history (会话历史)。基于 history 来实现的路由可以和最初的例子中提到的路径规则一样。

http://10.0.0.1/
http://10.0.0.1/about
http://10.0.0.1/concat
 

用户可能都察觉不到该访问地址是 Web 服务实现的路由还是前端实现的路由。

从性能和用户体验的层面来比较的话,后端路由每次访问一个新页面的时候都要向服务器发送请求,然后服务器再响应请求,这个过程肯定会有延迟。而前端路由在访问一个新页面的时候仅仅是变换了一下路径而已,没有了网络延迟,对于用户体验来说会有相当大的提升。

说了这么多的「路由基础」,该回头来说说 React Router 了。

配置路由

使用 React Router 来配置上面例子中的三个页面,每个页面分别对应着一个 React Component。

/about 页面的入口文件 about.js

import React from 'react';

class About extends React.Component {
componentDidMount () {
console.log('mount');
}

componentWillUnmount () {
console.log('un mount');
}

render () {
return (
<h3>This is About page.</h3>
);
}
};

export default About;

 

/concat 页面的入口文件 concat.js

 

import React from 'react';

const Concat = () => {
return (
<h3>This is Concat page.</h3>
);
};

export default Concat;

 

/ 首页对应的是 app.js,它也是整个 React Component 的入口文件。

 

import React from 'react';
import {Link} from 'react-router';

class App extends React.Component {
render () {
return (
<div>
<h1>React Router Demo</h1>
<hr />
<p>
by <a href="http://stylechen.com/" target="_blank">stylechen.com</a>
</p>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/concat">Concat</Link></li>
<li><Link to="/list/001">List 001</Link></li>
<li><Link to="/list/002">List 002</Link></li>
</ul>
{this.props.children}
</div>
)
}
};

export default App;

app.js 中的 Link 组件是 React Router 提供的组件,用于链接到相应页面。如果直接使用 a 标签的话相当于页面跳转了,而使用 Link 只是应用内的路由跳转,页面跳转意味着先重新加载整个页面,然后才是应用内部的路由跳转。

index.js 中包含了 route 的配置,同时在该文件中对 React Component 进行 render

import React from 'react';
import ReactDOM from 'react-dom';

import App from './component/app';
import About from './component/about';
import Concat from './component/concat';
import List from './component/list';

import {Router, Route, browserHistory} from 'react-router';

const router = (
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="concat" component={Concat} />
<Route path="list/:id" component={List} />
</Route>
</Router>
);

ReactDOM.render(
router,
document.getElementById('root')
);

 

Route 组件就是用于配置路由,path 属性用于配置路径,component 就是对应的 React Component。

Route 组件支持嵌套,嵌套时子组件的路径可以继承父组件的路径,上面的 about 嵌套后就成了 /about,当然也可以直接以根路径为开头。

此时再看看 app.js 中的 this.props.childrenAbout 和 Concat 两个页面组件其实就是以这种形式插入到父组件中,只是插入的时候用 React Router 提供的组件再包装了一下使它们可以支持路由。

Router组件还有一个重要的属性,那就是history,这可以配置使用history来实现路由,如果没有配置这个属性则默认使用hash

路由参数

假如我们有很多 list 页面,这些页面除了动态内容不同,其他的页面部分都相同,这个时候需要怎么配置路由和组件呢?

这种场景就需要用到路由的参数功能,增加一条包含参数的路由配置。

 
import List from './component/list';
 

注意 path 属性中的 :id 就是该路由的参数(param)。再来看看 List 页面的组件。

/list 对应了 list.js

import React from 'react';

class List extends React.Component {
render () {
return (
<div>
<h3>This is List page.</h3>
<p>The list page id is&nbsp;
<b style={{color: 'red'}}>{this.props.params.id}</b>
</p>
</div>
);
}
};

export default List;

在 List 组件中,可以直接通过 this.props.params.id 来访问实际的参数值(这里的id key 就和定义路径的 :id 相对应),React Router 将路由的数据都通过 props 传递给了页面组件,这样就可以非常方便的访问路由相关的数据了。

组件的生命周期

每个 React Component 都有生命周期,按照常规的策略,当调用父组件的 render 的时候,会将所有的页面子组件也进行 render,这种逻辑显然不合理了。那么当一个 React 的应用有了路由功能后,它的生命周期会如何处理呢?

当切换路由的路径的时候才去 render 对应的页面组件,给 About 绑定两个组件装载和卸载的事件,就可以测试出来了。

importReactfrom'react';

 
classAboutextendsReact.Component{
    componentDidMount(){
        console.log('mount');
    }
 
    componentWillUnmount(){
        console.log('un mount');
    }
 
    render(){
        return(
            ThisisAboutpage.
        );
    }
};
exportdefaultAbout;
 

在切换到 /about 页面的时候,会打印出 mount,而当离开页面的时候会打印出 un mount。路由的这种进入时装载组件离开时卸载组件的策略就可以做到合理利用「资源」,不会一下把所有的组件都装载进来使内存占用飙升,也不会离开时没有卸载而时内存泄漏。

React Router 还有很多比较方便 API,这里不一一列举,通过上面的文章基本能覆盖到常规的使用场景了,想了解更多使用方面查看 项目主页

本文的 demo 代码都已经托管在 github 上了,可以自己下载到本地浏览。

从 React Router 谈谈路由的那些事的更多相关文章

  1. React Router v4 页面传值的三种方法

    传值方法 1.props.params 使用React router定义路由时,我们可以给指定一个path,然后指定通配符可以携带参数到指定的path: <Route path='/user/: ...

  2. React 实践记录 03 React router

    Introduction 本文主要参考了react router 的官方文档. React Router是一套完整的配合React的路由解决方案,可能你已经知道前端路由,或者知道后端有路由的概念,如下 ...

  3. react router 4.0以上的路由应用

    thead>tr>th{padding:8px;line-height:1.4285714;border-top:1px solid #ddd}.table>thead>tr& ...

  4. react router @4 和 vue路由 详解(七)react路由守卫

    完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 12.react路由守卫? a.在之前的版本中,React Router 也提供了类似的 ...

  5. react router @4 和 vue路由 详解(全)

    react router @4 和 vue路由 本文大纲: 1.vue路由基础和使用 2.react-router @4用法 3.什么是包容性路由?什么是排他性路由? 4.react路由有两个重要的属 ...

  6. React Router 4.0 实现路由守卫

    在使用 Vue 或者 Angular 的时候,框架提供了路由守卫功能,用来在进入某个路有前进行一些校验工作,如果校验失败,就跳转到 404 或者登陆页面,比如 Vue 中的 beforeEnter 函 ...

  7. React初识整理(四)--React Router(路由)

    官网:https://reacttraining.com/react-router 后端路由:主要做路径和方法的匹配,从而从后台获取相应的数据 前端路由:用于路径和组件的匹配,从而实现组件的切换. 如 ...

  8. < react router>: (路由)

    < react router> (路由): 思维导图: Atrial   文件夹下的index.js 文件内容: import React, { Component } from 'rea ...

  9. react router @4 和 vue路由 详解(五)react怎么通过路由传参

    完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 7.react怎么通过路由传参? a.通配符传参(刷新页面数据不丢失) //在定义路由的 ...

随机推荐

  1. JSON Web Token(JWT)的详解

    1.传统身份验证和JWT的身份验证 传统身份验证: HTTP 是一种没有状态的协议,也就是它并不知道是谁是访问应用.这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户 ...

  2. LeetCode(128) Longest Consecutive Sequence

    题目 Given an unsorted array of integers, find the length of the longest consecutive elements sequence ...

  3. cf 1016C

    C. Vasya And The Mushrooms time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  4. 《Scrum实战》第1次课课后任务

    1.必做任务:从知行角度总结T平台 从知行角度总结T平台 头(知识,学习) 做得好的 宣贯会 引入敏捷思想 敏捷宣言 敏捷原则 质量风险前移原则 引入最佳实践 包括了XP的大部分实践 不足 项目管理框 ...

  5. Django two

    http://www.cnblogs.com/yuanchenqi/articles/6083427.html Django: 1.安装Django pip install  django 2.创建p ...

  6. 如何用treap写luogu P3391

    treap大法好!!! splay什么的都是异端 --XZZ 先%FHQ为敬 (fhq)treap也是可以搞区间翻转的 每次把它成(1~L-1)(L~R)(R+1~n)三块然后打标记拼回去 对于有标记 ...

  7. Apache下error.log文件太大的处理方法

    清除error.log.access.log并限制Apache日志文件大小的方法,在网上搜了下相应的资料,并按照如下步骤做了一遍,网站恢复正常   清除error.log.access.log并限制A ...

  8. php 操作excel

    <?php $dir=dirname(__FILE__);//查找当前脚本所在路径 require $dir."/db.php";//引入mysql操作类文件 require ...

  9. bat 文件读取乱码问题

    使用 for 循环 type file1.txt > file2.txt 文件读取后可能会出现乱码,需要在 bat 文件中设置 chcp 表示将批处理设置为 utf-8 编码,这样在生成文件和读 ...

  10. csa Round #70

    Digit Holes Time limit: 1000 msMemory limit: 256 MB   When writing digits, some of them are consider ...