React 路由概念详解

Posted YuLong~W

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 路由概念详解相关的知识,希望对你有一定的参考价值。

路由的理解

路由:

简单的说,路由是根据不同的 url 地址展示不同的内容或页面

  1. 一个路由就是一个映射关系(key:value)
  2. key为 路径,value可能是 function 或 component

路由分类:

  • 后端路由:
    • 用户请求的url导航到具体的html页面;每跳转到不同的URL,都是重新访问服务端,然后服务端返回页面,页面也可以是服务端获取数据,然后和模板组合,返回HTML,也可以是直接返回模板HTML,然后由前端js再去请求数据,使用前端模板和数据进行组合,生成想要的HTML。
    • 理解: value是 function用来处理客户端提交的请求
    • 注册路由: router.get(path, function(req, res))
    • 工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据
  • 前端路由:
    • 把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的
    • 浏览器端路由,value是 component用于展示页面内容
    • 注册路由: <Route path="/test" component={Test}>
    • 工作过程:当浏览器的path变为 /test时,当前路由组件就会变为Test组件

前端路由优点:

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

2、在某些场合中,用ajax请求,可以让页面无刷新,页面变了但url没有变化,用户就不能复制到想要的地址,用前端路由做单页面网页就很好的解决了这个问题。

前端路由缺点:

使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存。

前端路由

随着 ajax 的使用越来越广泛,前端的页面逻辑开始变得越来越复杂,特别是单页Web应用(Single Page Web Application,SPA))的兴起,前端路由系统随之开始流行。

SPA的理解:

  1. 单页Web应用(single page web application,SPA)
  2. 整个应用只有一个完整的页面
  3. 点击页面中的链接不会刷新页面,只会做页面的 局部更新
  4. 数据都需要通过ajax请求获取, 并在前端异步展现

1、从用户的角度看,前端路由主要实现了两个功能(使用ajax更新页面状态的情况下):

  • 记录当前页面的状态(保存或分享当前页的url,再次打开该url时,网页还是保存(分享)时的状态)
  • 可以使用浏览器的前进后退功能(如点击后退按钮,可以使页面回到使用ajax更新页面之前的状态,url也回到之前的状态)

2、作为开发者,要实现这两个功能,需要做到:

  • 改变url且不让浏览器向服务器发出请求
  • 监测 url 的变化
  • 截获 url 地址,并解析出需要的信息来匹配路由规则

以下为两种模式实现前端路由:

hash模式

这里的 hash 就是指 url 尾巴后的 # 号以及后面的字符。这里的 # 和 css 里的 # 是一个意思。hash也称作锚点,本身是用来做页面定位的,可以使对应 id 的元素显示在可视区域内。

由于 hash 值变化不会导致浏览器向服务器发出请求,因此不会刷新页面,从而实现无刷新的效果。所以在 html5 的 history 出现前,基本都是使用 hash 来实现前端路由。

1、hash属性: 在当前页面中,可以通过:window.location.hash = 'edit'来实现改变当前 url 的hash值,执行上述的hash赋值,页面的url发生改变。

例如:赋值前:http://localhost:3000 赋值后:http://localhost:3000 /#edit

2、hashchange 事件: hash 改变会触发 hashchange 事件,浏览器的进后退也能对其进行控制。有了监听事件,且改变hash页面不刷新,这样就可以在监听事件的回调函数中,执行我们展示和隐藏不同UI显示的功能,从而实现前端路由。

window.addEventListener('hashchange', function(){
    // 监听hash变化,点击浏览器的前进后退会触发
})

此外,要改变页面的hash值,还可以通过 html的 <a> 标签 来实现页面跳转:<a href="#edit"></a>

hash 的缺点:

  • 搜索引擎对带有hash的页面不友好
  • 带有hash的页面难以追踪用户的行为

history模式

已经有 hash 模式了,而且 hash 能兼容到IE8, history 只能兼容到 IE10,为什么还要搞个 history 呢?

原因:

1、hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。

2、hash 的传参是基于 url的,如果要传递复杂的数据,会有体积的限制,而history 模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。

相关API:

history的属性:

  • length:返回在会话历史有多少条记录,包含了当前会话页面。如果打开了一个新的tab,那么这个length会加1
  • state:保存了popState等事件方法,所传递过来的属性和对象(后面会在pushState和replaceState方法中详细的介绍)

history的方法:

  • history.back():返回浏览器会话历史中的上一页,跟浏览器的 回退 按钮功能相同
  • history.forword():指向浏览器会话历史中的下一页,跟浏览器的 前进 按钮相同
  • history.go(n):可以跳转到浏览器会话历史中的 指定的某一个记录页,n可为正数或者负数
  • history.pushState(state, title, url):pushState可以 将给定的数据压入到浏览器会话历史栈中,该方法接受3个参数,对象,title,和一串url,值得注意的是,pushState调用后会改变页面的url,但是不会刷新页面
    • state:需要保存的数据,这个数据在触发popstate事件时,可以在event.state里获取
    • title:标题,基本没用,一般传 null
    • url:设定新的历史记录的 url。新的 url 与当前 url 的 origin 必须是一樣的,否则会抛出错误。url可以是绝对路径,也可以是相对路径。
    • 例如: 当前url是 https://www.baidu.com/a/,执行 history.pushState(null, null, './qq/'),则变成 https://www.baidu.com/a/qq/,执行 history.pushState(null, null, '/qq/'),则变成 https://www.baidu.com/qq/
  • history.replaceState(state, title, url):replaceState 将当前的会话页面的url替换成指定的数据,replaceState后也会改变当前页面的url,但是也不会刷新页面。

pushState和replaceState的不同点:前者是压入浏览器的会话历史栈中,使得History.length加1,而后者是替换当前的这条会话历史,因此不会增加History.length

history的优点:

  • 对搜索引擎友好
  • 方便统计用户行为

缺点:

  • 兼容性不如hash
  • 需要后端做相应的配置,否则访问子页面回出现404错误。

react-router-dom

React实现页面路由的模块:react-router-dom

  • react的一个插件库
  • 专门用来实现一个SPA应用
  • 基于react的项目基本都会用到此库

路由的基本使用

下载react-router-dom: npm install react-router-dom

  • 1.明确好界面中的导航区、展示区
  • 2.导航区的a标签改为Link标签<Link to="/xxxxx">Demo</Link>
  • 3.展示区写Route标签进行路径的匹配<Route path='/xxxx' component={Demo}/>
  • 4.<App>的最外侧包裹了一个<BrowserRouter><HashRouter>

效果展示:

首先创建两个组件,然后在App.js文件中引用, 接着到index.js文件中注册App组件,最后用index.html文件渲染到页面上

App.js:

import React, { Component } from 'react'
import {Link,Route} from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'

export default class App extends Component {
	render() {
		return (
			<div>
				<div className="row">
					<div className="col-xs-offset-2 col-xs-8">
						<div className="page-header"><h2>React Router Demo</h2></div>
					</div>
				</div>
				<div className="row">
					<div className="col-xs-2 col-xs-offset-2">
						<div className="list-group">

							{/* 原生html中,靠<a>跳转不同的页面 */}
							{/* <a className="list-group-item" href="./about.html">About</a>
							<a className="list-group-item active" href="./home.html">Home</a> */}

							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
							<Link className="list-group-item" to="/about">About</Link>
							<Link className="list-group-item" to="/home">Home</Link>
						</div>
					</div>
					<div className="col-xs-6">
						<div className="panel">
							<div className="panel-body">
								{/* 注册路由 */}
								<Route path="/about" component={About}/>
								<Route path="/home" component={Home}/>
							</div>
						</div>
					</div>
				</div>
			</div>
		)
	}
}

Home组件:

import React, { Component } from 'react'

export default class About extends Component {
	render() {
		return (
			<h3>我是About的内容</h3>
		)
	}
}

About组件:

import React, { Component } from 'react'

export default class About extends Component {
    render() {
        return (
            <h3>我是About的内容</h3>
        )
    }
}

index.js文件:

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {BrowserRouter} from 'react-router-dom'

ReactDOM.render(
    <BrowserRouter> // <App>的最外侧包襄了一个<BrowserRouter>或<HashRouter>
        <App/>
    </BrowserRouter>,
    document.getElementById('root')
)

index.html文件:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>react脚手架</title>
		<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
		<link rel="stylesheet" href="/css/bootstrap.css">
	</head>
	<body>
		<div id="root"></div>
	</body>
</html>

以上是关于React 路由概念详解的主要内容,如果未能解决你的问题,请参考以下文章

React路由的详解

React路由的详解

React路由的详解

使用具有不同片段字段的相同中继根查询的多个 react-router-relay 路由

导致资产预编译在heroku部署上失败的代码片段

React路由详解