前言
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
还木有评论哦,快来抢沙发吧~