一、相关依赖包
Router 路由是react全家桶【react+redux + router】中的一员,在项目中用于分发组件,资源组织。下面我们看使用路由时相关的包。
主要包含react-router 和 react-router-dom两个包。
在项目开发中一般使用的像Router,Route,Redirect,Switch…都是来自react-router。因此一般基于浏览器环境的开发只需要安装react-router-dom ,安装时会自动安装react-router依赖。非浏览器环境的开发可以单独安装react-router。
安装命令:
npm install react-router-dom --save --dev-save
npm install react-router --save --dev-save // 非浏览器环境的开发
npm install react-router-dom --save --dev-save
导入包及常用组件
import { BrowserRouter/HashRouter as Router, Route, RouteProps, Link, NavLink, Redirect, Switch,RouteComponentProps,withRouter } from 'react-router-dom';
相当于
import { BrowserRouter/HashRouter as Router, Route, RouteProps, Redirect, Switch,RouteComponentProps,withRouter } from 'react-router';
import { Link, NavLink} from 'react-router-dom';
二、路由使用方式
1、根路由使用 BrowserRouter或HashRouter 包裹
import { BrowserRouter或hashRouter as Router, Route } from "react-router-dom";
const store = createStore(rootReducer, applyMiddleware(...defaultMiddlewares));
function App() {
return (
);
}
在项目的根路由中应该使用 BrowserRouter或HashRouter组件 进行包裹路由的组件。简单介绍下原因:
它可以让你向应用中快速地添加视图和数据流,同时保持页面与URL间的同步。
在没有使用react-router时
为了让我们的URL解析变得更智能,我们需要编写很多代码来实现指定URL应该渲染哪一个嵌套的UI组件分支:,,,等等。
`App -> About`
`App -> Inbox -> Messages -> MessageApp -> Inbox -> Messages -> Stats`。
使用路由之后:React Router知道如何为我们搭建嵌套的UI,因此我们不用手动找出需要渲染哪些组件。举个例子,对于一个完整的路径,React Router会搭出出。/about
在内部,路由器会将你树级嵌套格式的转变成路由配置。
要详细了解可参考文档:使用React-router前后对比 http://react-guide.github.io/react-router-cn/docs/Introduction.html
因此使用React-Router后会大大方便,提高效率。
区别
BrowserRouter是服务端路由,HashRouter是客户端路由
BrowserRouter 的url路径 标准的URL路径 / ,hash路由 不是通过斜杠/方式,而是通过#方式
如果支持一些低版本浏览器时,用斜杠方式浏览器会页面不刷新,这时就需要使用hash路由【HashRouter】。
还有一种内存路由【MemoryRouter】,路由不会反应到url上,服务器段渲染时会用但是前端也可以用
import {MemoryRouter} from ‘react-router’
2、路由嵌套
react router 4.0以后路由嵌套方式为在需要嵌套路由的component中添加新的路由。这也是组件资源组织的一种方式。按照功能划分路由,按照路由组织代码结构。
import * as React from "react";
import { Route, Switch } from "react-router-dom";
const AppComponent = ({ match }) => {
return (
);
};
const history = ({ location }) => {
return (
);
};
3、路由匹配原则方式
关于路由匹配url路径相关的 组件有 Route、Link、NavLink、Redirect、Switch
Route、Switch、Link、NavLink、Redirect
-----------------------------------------------------------------
当不写path时是总会加载。可以用在Swith排他组件中作为默认匹配路由,放在最后的位置
-----------------------------------------------------------------
这个组件一般与Route配合使用,用于只显示匹配到的第一个组件。因此Switch的作用就是只渲染匹配到的第一个组件。
-----------------------------------------------------------------
第一季度
第一季度
这两个用于链接点击时的路由跳转,NavLink在active后会有 activeClassName的样式。
-----------------------------------------------------------------
这个用于在ui组件渲染时路由跳转,如登录成功之后转发路由至首页的情况
-----------------------------------------------------------------
路由匹配过程解析
原理:
url与route的path匹配时主要是基于node的url.parse。先通过location.pathname获取到url的pathname,在对
pathname进行数组拆分 pathname.split("/"),得到url的访问路径数组。再对Route的path同样进行
path.split("/")拆分得到 path的路径数组。匹配从根节点开始 每一级Route path的路径数组与 url的访问路径
数组进行每个元素逐位对比。匹配相同则返回true,显示组件。而在匹配中Route的strict为false也就是非严格
模式下如果要匹配的路径已经以斜杠结束[path="/history/"],为了保持一致性,Router包组件自动删除了最后
一个斜杠[path="/history"]。斜杠在路径匹配的末尾有效,而不是在中间。而在匹配中Route的strict为true,
这时path路径会开启严格模式,会进行最后一位斜杠的空值位置的比较,路径中的最后一个位为斜杠时同时
为最后一级的路径,则url访问的地址也必须为斜杠结尾。路径中最后一位没有斜杠时不影响。
exact 为精确模式,不写的情况下默认为false,当为true时,组件匹配路径只能到exact这一及组件。因此一
般属性是在组件显示的末节点添加,也就是添加exact的组件中没有子路由。与组件是否为最后一个组件节
点有关。
strict 为严格模式,不写的情况下默认为false,作用为在path解析时是否匹配path路径中的最后一个斜杠的空
值位置。
例如嵌套路由:
Route path=/app component={History} --根路由
Route path= /history component={Quarter} --中间路由
Route path= /firstQuarter exact component={firstQuarter} --末节点路由
对于组件firstQuarter 来说,它的路由地址为 每一级路由的拼接 /app/history/firstQuarter
当我们使用 http://ip:port/app/history/firstQuarter 访问组件firstQuarter时,进行了三次匹配,
1、从路由根节点/app开始匹配,匹配方式为模糊匹配,只要路径中为以/app开始就能进入到History组件中
2、当匹配第二层路由/history时,匹配方式为模糊匹配,只要路径中为以/app/history开始时就能进入组件
Quarter
3、当匹配第三层路由/firstQuarter时,匹配方式为精确匹配,路径必须为以/app/history/firstQuarter开始时才
能进入组件firstQuarter
每个url的路径匹配都是从路由根节点开始。
4、路由path多路径匹配同一组件
写法:
-----------------------------------------------------------------
-----------------------------------------------------------------
5、组件获取路由地址属性方式
这里涉及到两个组件
import { RouteComponentProps,withRouter } from 'react-router-dom';
第一个RouteComponentProps 是组件通过props继承方式 获取 history/ location/ match/ staticContext这些属性。同时也可以进行路由参数的传递。
export interface IPointsProps extends StateProps, DispatchProps, RouteComponentProps<{ url: string }> {}
export interface IPointsState extends IPaginationBaseState {
search: string;
tooltipOpen: boolean;
popoverOpen: boolean;
}
export class Points extends React.Component {
state: IPointsState = {
search: '',
tooltipOpen: false,
popoverOpen: false,
...getSortState(this.props.location, ITEMS_PER_PAGE)
};
第二个withRouter通过高阶组件的封装时组件具有RouteComponentProps的属性 history/ location/ match/ staticContext,而不用继承。
const headerDiv = ({location}) => {
const { Header } = Layout;
let selectkeyvalue;
if (location.pathname.includes("history")) {
alert("1")
} else {
alert("2");
}
return (
);
};
export default withRouter(headerDiv);
6、路由传参及取值
第一种通配符方式
参考链接http://react-guide.github.io/react-router-cn/docs/guides/basics/RouteMatching.html
路由路径是匹配一个(或一部分)URL 的 一个字符串模式。大部分的路由路径都可以直接按照字面量理解,除了以下几个特殊的符号:
– 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数
// 匹配 /hello/michael 和 /hello/ryan
// 匹配 /hello, /hello/michael 和 /hello/ryan
// 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg
如果一个路由使用了相对路径,那么完整的路径将由它的所有祖先节点的路径和自身指定的相对路径拼接而成。使用绝对路径可以使路由匹配行为忽略嵌套关系。
在组件中获取参数
this.props.match.params.name
优点:在刷新页面的时候,参数不会丢失。
缺点:只能传字符串
第二种state 方式
组件路由
Link组件中跳转传参
Link to={
{ pathname: `/new`, state: "xiaoxi2" }}>
在组件中获取参数
this.props.location.state.name
this.props.location.state
-----------------------------------------------------------------
componentWillMount() {
console.log(this.props.location.state.name)
console.log(this.props.location.state)
}
优点:优雅,可传对象和字符串
缺点:当通过链接点击打开页面,这时刷新页面不会参数丢失,而当通过相同的链接地址在新窗口打开页面则会丢失数据,页面出错this.props.location拿不到state的数据。
第三种search方式
组件路由
Link组件中跳转传参
query
在组件中获取参数
location的属性
{pathname: "/history/second", search: "?search=dd", hash: "", state: undefined, key: "hpzd44"}
取值:
this.props.location.search =》 ?search=dd
缺点:刷新页面,参数不会丢失,参数需要字符串解析
第四种history.push方式
(method) History.push(path: string, state?: any): void (+1 overload)
this.props.history.push("/history","123");
handleClick = () => {
console.log("点击");
this.props.history.push("/");
}