create-react-app中使用react-router-dom实现路由跳转

react

0x00 写在前面

  说来很奇怪,之前用create-react-app写的web网页,结合ant desgin布局写的一个导航栏路由跳转。启动项目之后,首页有数据展示,点击导航栏可以跳转。但是!在整合了electron和react之后,启动项目之后首页空白,默认导航栏位置错误,要人为点击一下才有数据展示。这样用户体验真的真的很不友好。也是查了好久好久才解决了这个问题,于是决定写一篇博客,总结一下react-router-dom。

0x01 react-router-dom的安装与使用

  react-router-dom的使用有两种方式。

1.1 使用npm

1
$ npm install --save react-router-dom
  • js文件中
1
2
3
4
5
6
7
// using ES6 modules
import { BrowserRouter, Route, Link } from 'react-router-dom'//推荐使用
// using CommonJS modules
const BrowserRouter = require('react-router-dom').BrowserRouter
const Route = require('react-router-dom').Route
const Link = require('react-router-dom').Link

1.2 使用unpkg

1
<script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>

  注意的是,这种方式还需要引入react的一些核心文件和依赖文件。不推荐使用这种方式。

0x02 react-router-dom与react-router的区别

  • react-router: 实现了路由的核心功能
  • react-router-dom: 基于react-router,加入了在浏览器运行环境下的一些功能,例如:Link组件,会渲染一个a标签,Link组件源码a标签行; BrowserRouter和HashRouter组件,前者使用pushState和popState事件构建路由,后者使用window.location.hash和hashchange事件构建路由。

  接下来将介绍react-router-dom的一些组件

0x03 react-router-dom的详细介绍

3.1 HashRouter和BrowserRouter

  这两个API两个是路由的基本,需要将它们包裹在最外层,两者只需要选其一。

3.1.1 HashRouter

  使用URL的哈希部分(即window.location.hash)的来保持UI与URL同步。注意:哈希历史记录不支持location.key或location.state。如果你使用过react-router2或3或者vue-router,你经常会发现,在浏览器打开页面,其url中会有个#,例如localhost:3000/#,HashRouter就会出现这种情况,它是通过hash值来对路由进行控制。如果使用HashRouter,路由就会默认有这个#。

1
2
3
<HashRouter>
<Route path="/" componet={Home}></Route>
</HashRouter>

3.1.2 BrowserRouter

  很多情况下不需要这个#,这时就需要用到BrowserRouter。它的原理是使用HTML5历史记录API(pushState,replaceState和popstate事件)的来保持UI与URL的同步, 下面将主要结合它来讲解。如果文件放在服务器的二级目录下就可以使用它。

1
2
3
4
5
6
7
8
<BrowserRouter
basename="app"
forceRefresh=true
getUserConfirmation=window.confirm
keyLength=9
>
<Link to="/about">About</Link>
</BrowserRouter>

3.2 Route

  Route用于控制路径对应显示的组件。常用的有exact、path以及component属性。

  • exact用于严格匹配,控制匹配到/路径时不会再继续向下匹配;
  • path标识指向的路由路径;
  • component表示要跳转的路径对应的显示组件;

  Route会有三大props,分别是location、history、match;

3.2.1 history

  history 指的是 history 包,它是 React Router 的两个主要依赖之一(除了 React 本身),并且提供了几种不同的实现方式,用于在各种环境中管理 JavaScript 中的会话历史。
  history分成以下三种

  • browser history - 针对 DOM 环境,用于支持 HTML5 history API 的浏览器
  • hash history - 针对 DOM 环境,用于传统的旧式(低版本) 浏览器
  • memory history - history 在内存上的实现,用于测试以及 React Native 等非 DOM 环境

  history对象具有以下属性和方法:

  • length - number 历史堆栈中的条目数
  • action - string 当前的导航操作(push、replace 或 pop)
  • location - object 当前访问的位置信息,见下文
  • push(path, [state]) - function 将一个新条目推入到历史堆栈中
  • replace(path, [state]) - function 替换历史堆栈中的当前条目
  • go(n) - function 将历史堆栈中的指针移动 n 个条目
  • goBack() - function 返回到上一个页面,相当于 go(-1)
  • goForward() - function 进入到下一个页面,相当于 go(1)
  • block(prompt) - function 阻止导航(请参阅 history 文档)

  history 对象是可变的。因此建议从 渲染组件时接收的属性中直接访问 location,而不是通过 history.location 进行访问。这样可以保证 React 在生命周期中的钩子函数正常执行。

1
2
3
4
5
6
7
componentWillReceiveProps(nextProps) {
// true
console.log(nextProps.location !== this.props.location);
// false,因为 history 是可变的。
console.log(nextProps.history.location !== this.props.history.location);
}

3.2.2 location

  location 代表应用程序的位置。如当前的位置,将要去的位置,或是之前所在的位置。
  location具有以下的属性:

  • pathname - string URL 路径
  • search - string URL 中的查询字符串
  • hash - string URL 中的 hash 片段
  • state - object 存储至 location 中的额外状态数据,仅在 browser history 和 memory history 中有效。
      Router 将在以下几个地方提供 location 对象:
  • 在 Route component 中,以 this.props.location 方式获取
  • 在 Route render 中,以 ({ location }) => () 方式获取
  • 在 Route children 中,以 ({ location }) => () 方式获取
  • 在 withRouter 中,以 this.props.location 方式获取

  location 对象永远不会发生改变,因此可以在生命周期钩子函数中使用 location 对象来查看当前访问地址是否发生改变。

1
2
3
4
5
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
// 已经跳转了!
}
}

3.2.3 match

  Match是在使用Router之后被放入props中的一个属性,在class创建的组件中我们需要通过this.props.match来获取match之中的信息。match中包含的信息如下。

  • params: object 路径参数,通过解析 URL 中的动态部分获得键值对
  • isExact: bool 为 true 时,整个 URL 都需要匹配
  • path: string 用来匹配的路径模式,用于创建嵌套的 Route
  • url: string URL 匹配的部分,用于嵌套的 Link

  在获取id时经常使用match。

  两者都可以控制路由跳转,不同点是NavLink的api更多。

  主要api是to,to可以接受string或者一个object,来控制url,表示路由要跳转的路径。

1
2
3
4
5
6
7
<Link to="/home" />
<Link to={{
pathname: '/home',
search: '?page=1',
hash: '#the-hash',
state: { fromDashboard: true }
}} />

  这时点击Link就会跳转到home页面。

3.3.2 NavLink:

  它可以为当前选中的路由设置类名、样式以及回调函数等。

1
2
3
4
5
6
7
8
9
10
<BrowserRouter>
<div>
<ul>
<li>
<NavLink exact activeClassName="selected" to="/home/1">首页</NavLink>
</li>
</ul>
</div>
<Route path="/home/:1" componet={Home}></Route>
</BrowserRouter>

  exact用于严格匹配,匹配到/则不会继续向下匹配;to则是控制跳转的路径,activeClassName是选中状态的类名,可以为其添加样式。我们通过在/home后面添加1来向路由中传递信息,这结合了上面Route中的/second/:id,线面的1234内容显示需要用到match。

3.4 Switch

  Switch常常会用来包裹Route,它里面不能放其他元素,表示一次只能显示一个路由。用于渲染与路径匹配的第一个子 。但与不同的是, 只会渲染一个路由。而定义一系列 时,所有被匹配到的 将都会在页面被渲染出来。

1
2
<Route exact path="/" component={Service} />
<Route path="/homepage" component={Homepage} />

  像这种情况,exact匹配到’/‘就不会再向下匹配,当url为”http://localhost:3000/"时,两个页面都会被匹配到;(匹配不到页面)Switch有两个属性

  • location: object。用于匹配子元素而不是当前历史位置(通常是当前的浏览器 URL)的 location 对象。
  • children: node。 的子元素应该是 。只有第一个匹配当前路径的组件会被渲染。当 中包含 时,可以使用任何 拥有的路径匹配属性:path、exact 和 strict。from 只是 path 的别名。

3.5 Redirect

  Redirect有四个属性

  • to:string。链接到的路径名或位置。

  • to:object。要链接的位置。

  • push:bool。当为true时,重定向会将新条目推入历史记录,而不是替换当前条目

  • from:string。要重定向的路径名。用于在内部渲染时匹配位置。

0x04 结合小例子的讲解

  在这个小例子中,被放在最外层;的子节点是,表示当前只会渲染一个路由,如果不使用的话,两个组件将会以同时渲染在一个页面上;再接下来是,exact表示精确匹配到’’,只要匹配到’/‘就不会再往下匹配了,这时候就会出现将homepage和device两个页面都匹配到,这种情况下,如果不加Switch,就会按照先后顺序将两个组件都显示到同一个页面上;在加上switch的情况下,也会因为匹配到两个路径中有’/‘的组件而显示空白,这个时候,就需要加上Redirect,只显示第一个被匹配到的路径对应组件的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<Menu.Item key="1">
<Link to="/service">设备</Link>
</Menu.Item>
<Menu.Item key="2">
<Link to="/homepage">取证</Link>
</Menu.Item>
<BrowserRouter>
<Switch>
<Route exact path="/" component={Device}>
</Route>
<Route path="/homepage" component={Homepage} />
<Redirect to="/" />
</Switch>
</BrowserRouter>

Miss Me wechat
light