React 路由

前端这点事 74 0

前言

react-router-dom版本:5.0.1

types/react-router-dom版本:4.3.4

为什么要使用路由

这是一个重要的问题,我们必须在使用之前搞清楚。这对任何技术都一样,因为你只有弄清楚了这个问题,才能判断你是否真的需要它。

那么我们为什么要使用路由呢?

官方的解释是:

React Router 保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。

说白了就是使用真实的URL实现对组件的加载控制,使我们的单页面应用也能使用URL访问。因此,我们的代码就可以更加优雅。

当然,仅为了这份优雅,不值得我们下功夫去学习它,它还有其它优点,我们接着往下看。

原理

React Router 是建立在history之上的。这个history其实就是window.history,我们可以在控制台直接打印出来。

history
History {length: 39, scrollRestoration: "auto", state: {…}}

history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为Location对象,然后 router 使用它匹配到路由,最后正确地渲染对应的组件。于是,我们的单页面应用也可以神奇的使用浏览器的前进/后退了。

同时,我们注意到,history打印输出中有个state属性,它可以用来保存操作状态。

至此,我们可以简单总结一下React Router的好处了:

1.优雅地实现组件的加载控制;

2.可以监听浏览器地址栏的变化,可以使用浏览器的前进/后退功能;

3.可以保存操作状态。

OK,弄明白了路由是怎么回事之后,我们接下来就说说怎么使用吧。

安装

React Router已被拆分成三个包:react-router,react-router-dom和react-router-native。其中,react-router包提供核心的路由组件与函数,我们不需要直接安装它,另外两个提供运行环境(浏览器与react-native)所需的特定组件,它们会加载react-router依赖,并暴露其对象和方法。因此,我们这里使用react-router-dom。

npm install -D react-router-dom

如果你配置了TypeScript环境,需要在安装types依赖:

npm install -D @types/react-router-dom

动态路由和静态路由

在react-touter v4以前,react-router使用静态路由。所谓静态路由,就是所有的路由信息都要配置在一张静态路由表上面;而动态路由不是作为配置文件存储在外部,则视路由为一个普通的组件,这样更加契合react的一切皆组件的设计。

BrowserRouter

BrowserRouter替代了原来的Router,提供了更好的封装,它主要是封装了history的创建,这样,我们就不需要在自己创建history对象了。类似这样:

import { BrowserRouter } from 'react-router-dom'

React.render((
<BrowserRouter>
    <Switch>
        <Route exact path="/" component={ DispatchPage }></Route>
        <Route path="/dispatch" component={ DispatchPage }></Route>
        <Route path="/map" component={ MapPage }></Route>
    </Switch>
</BrowserRouter>
), document.body)

注意:Router只能有一个子孩子。

BrowserRouter的地址是这样的:

http://localhost:8080/about

它跟一般的服务端地址一样,因此,而服务器没有这个路径,因此会出现can't GET /about这种错误。我们需要修改服务端配置,这里使用webpack-dev-server搭建的本地服务,我们需要在devServer配置项中增加一个配置:

devServer: {
  ...
  historyApiFallback: true
}

Route

Route是路由配置的具体实现,它指定当路径匹配的时候渲染哪一个UI。我们介绍一下它的几个主要属性。

path:path用于指定路径,如果不写,则总是被匹配。

exact:exact为TRUE时,表示完全匹配。

strict:strict用于匹配尾部斜杠,此时,exact必须也是TRUE。

NavLink和Link

Link指定链接到的路径名或位置,我们一般使用NavLink。例如:

<div>
    <span title="dispatch"><NavLink to="/dispatch">Dispatch</NavLink></span><br/>
    <span title="map"><NavLink to="/map">Map</NavLink></span><br/>
</div>

Switch

有<Switch>标签,则其中的<Route>在路径相同的情况下,只匹配第一个,这个可以避免重复匹配。有的时候它也需要和exact配合使用,否则会有永远匹配不上某个路由的情况发生。

Redirect

Redirect为重定向,渲染将导航到新位置。新位置将覆盖历史堆栈中的当前位置。例如:

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

其中,to表示要重定向到的网址。

跳转前确认

React Router 提供一个 routerWillLeave 生命周期钩子,这使得 React 组件可以拦截正在发生的跳转,或在离开 route 前提示用户。routerWillLeave 返回值有以下两种:

1.return false 取消此次跳转

2.return 返回提示信息,在离开 route 前提示用户进行确认。

使用方式如下:

import { Lifecycle } from 'react-router'

const Home = React.createClass({

  // 假设 Home 是一个 route 组件,它可能会使用   // Lifecycle mixin 去获得一个 routerWillLeave 方法。   mixins: [ Lifecycle ],

  routerWillLeave(nextLocation) {
    if (!this.state.isSaved)
      return 'Your work is not saved! Are you sure you want to leave?'
  },

  // ... 
})

使用tomcat服务器

tomcat服务器和node服务本质上没有什么区别,主要在于URL不同,上面我们已经提到,node服务的地址一般是:

http://localhost:8080/about

而tomcat的地址会再增加一个文件夹目录,像这样:

http://localhost:8080/dist/about

由于多了个目录,React路由就找不到了,我们需要在路由中添加基础路径,像这样:

<BrowserRouter basename="/dist">

好了,页面可以访问了,但紧接着我们会发现新的问题:当我们刷新页面时,页面就找不到了。

这是因为刷新时,是向服务器直接请求该URL,而不是通过React路由来更改的,因此,服务器无法匹配到。解决方案就是在服务端配置404重定向到index.html,剩下的就交由React路由来解决了。做法很简单,我们只需要在tomcat部署的目录下增加一个文件:WEB-INF/web.xml,并在其中添加如下代码:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">

    <error-page>
        <error-code>404</error-code>
        <location>/index.html</location>
    </error-page>

</web-app>

好了,重启服务器,刷新成功!

注意:只有BrowerRouter才会出现该问题。

 

 

 

 

标签: React

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~