这东西好像和vue里面的路由确实不一样;react-router非常复杂整体,比vue-router强大很多
React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步
React Router 知道如何为我们搭建嵌套的 UI,因此我们不用手动找出需要渲染哪些 组件,即,向页面返回了一个路由组件(即默认导出路由,然后放在ReactDOM里面),当路由组件检测到地址栏与Route的path匹配时,就会自动渲染对应的组件来加载响应的页面。举个例子,对于一个完整的 /about 路径,React Router 会搭建出
在内部,router 会将你树级嵌套格式的 转变成路由配置。但如果你不熟悉 JSX,你也可以用普通对象来替代
一、引入
使用react router是需要安装的,下面一些是react-router库:4.0是多包管理
react-router React Router 核心
react-router-dom 用于 DOM 绑定的 React Router(一般引用这一个即可)
react-router-native 用于 React Native 的 React Router
react-router-redux React Router 和 Redux 的集成
react-router-config 静态路由配置帮助助手
- (1)安装
- React-router:
npm install react-router --save
- React-router-dom:
npm install react-router-dom --save
,使用npm安装react-router-dom的时候,不需要npm安装react-router- (2)API对比
- React-router:提供了router的核心api。如Router、Route、Switch等,但没有提供有关dom操作进行路由跳转的api
- React-router-dom: 提供了BrowserRouter、Route、Link等api,可以通过dom操作触发事件控制路由。在react-router的基础上扩展了可操作dom的api(比如点击一个按钮完成跳转)
import {Router,Route,browserHistory,Switch} from 'react-router'
import {BrowserRouter as Router,Link,Switch,Route,useRouteMatch,useParams} from "react-router-dom";
- (3)this.props.children: 这个东西很好用,children的值就为父组件中写在子组件标签中的内容
// 下面这个是子组件,children为父组件传过来的。
return (
<div className='main-layout'>
{this.props.children}
</div>
);
二、基础
1、路由配置
路由配置是一组指令,用来告诉 router 如何匹配 URL以及匹配后如何执行代码。配置方法有两种,一种方式为使用jsx语法,还一种是使用原生 route 数组对象
// jsx方式的路由配置
import { Redirect } from 'react-router'
ReactDOM.render((
<Router>
<Route path="/" component={App}>
<IndexRoute component={Dashboard} />
<Route path="inbox" component={Inbox}>
<Route path="/messages/:id" component={Message} />
{/* 跳转 /inbox/messages/:id 到 /messages/:id */}
<Redirect from="messages/:id" to="/messages/:id" />
</Route>
</Route>
</Router>
), document.body)
// 原生route数组的路由配置
const routeConfig = [
{ path: '/',component: App,
indexRoute: { component: Dashboard }, // 这个是默认路由
childRoutes: [
{ path: 'inbox',component: Inbox,
childRoutes: [
{ path: '/messages/:id', component: Message },
{ path: 'messages/:id',
onEnter: function (nextState, replaceState) {
replaceState(null, '/messages/' + nextState.params.id)
}}]}]}
]
ReactDOM.render(<Router routes={routeConfig} />, document.body)
2、路由匹配原理
- 关于路径有下面几个特殊符号
- :paramName: 匹配一段位于 /、? 或 # 之后的 URL。 命中的部分将被作为一个参数
- (): 在它内部的内容被认为是可选的
- *: 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数
<Route path="/hello/:name"> // 匹配 /hello/michael 和 /hello/ryan
<Route path="/hello(/:name)"> // 匹配 /hello, /hello/michael 和 /hello/ryan
<Route path="/files/*.*"> // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg
3、Histories
react默认是history模式的。然后,还有其它三种模式browserHistory(默认的)、hashHistory(这个就是hash模式)、createMemoryHistory
// 从 React Router 中引入它们
import { browserHistory, Router, Route, IndexRoute } from 'react-router'
4、默认路由(IndexRoute)与 IndexLink
在react中,路由跳转用的是
<link>
标签;类似于vue中精确加载是在标签里面加一个exact,在react里面使用的是<IndexLink>
标签
<Link to="/">Home</Link>
<IndexLink to="/">Home</IndexLink>
三、react-router API
注:下面的这些API是关于JSX写法的路由
1、HashRouter和BrowserRouter
这两个是路由容器,即写在外面的,来定义是什么模式的路由
// import { HashRouter, Route, Switch } from "react-router-dom";
<HashRouter>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/detail" component={Detail}/>
</Switch>
</HashRouter>
2、Switch
只渲染第一个匹配到的路由组件,Switch下的子节点只能是 Route 或 Redirect 元素。只有与当前访问地址匹配的第一个子节点才会被渲染
3、Route
Route 主要用于控制路径对应显示的组件,编程式导航三个路由属性是。exact:精准匹配,不再向下匹配,path:标识路由的路径,component:路径对应显示的组件
4、Link和NavLink
路由导航:NavLink区别在于有一个属性用来显示跳转选中的样式。用Link标签跳转而不用a标签跳转的原因是;a标签跳转的话相当于是跳转到另外一个页面,所以会刷新当前页面,要阻止这样就只有阻止a标签的默认行为;而link标签不会有这样的行为
import { Link } from "react-router-dom";
<Link to="/about">About</Link>
5、withRouter
withRouter可以包装任何自定义组件,将react-router 的 history,location,match 三个对象传入。
无需一级级传递react-router 的属性,当需要用的router 属性的时候,将组件包一层withRouter,就可以拿到需要的路由信息。
主要用于子组件
6、match
- this.props.match: 用于获取路由的参数信息。如果要获取当前的路径的话,建议用window上面的location属性
console.log(this.props.match.params.id)
location.origin // 表示域名,"http://localhost:8000"
location.href // 表示url,"http://localhost:8000/Demo/2"
location.pathname // 表示后面的路由路径,"/Demo/2"
7、location
用来存放当前的路径的信息。直接用window上面的location属性,感觉差不多的
const { pathname } = this.props.location;
8、history
可以用来手动跳转到页面。使用这个history的时候,有时候会报错 history为undefined,所以这个时候需要用
withRouter()()
这个高阶组件来包裹当前组件
- props.history.push(params): 这个push()函数的params参数,可以为一个字符串也可以为一个对象。
- 参数为字符串:为字符串的时候,就代表要跳转的目标路由路径
- 参数为对象:为对象的时候,就可以 给目标路由传参了
- pathname属性:表示要跳转的目标路由路径。 类型:string
- query属性:表示要传给目标路由的参数。不过参数会被放到地址栏。 类型:object
- state属性:也是传给目标路由的参数。参数是加密的,不会放到地址栏。 类型:object
- 组件中获取传过来的路由参数:如果是query传过来的对象参数,就用
this.props.location.query
(默认为{}); 如果是state传过来的对象参数,就用this.props.location.state
(默认为undefined);
this.props.history.push('/user/list')
// query传参
this.props.history.push({ pathname : '/sort' ,query : { name: ' sunny'} })
this.props.location.query.name; // 接收参数
// state传参
this.props.history.push({ pathname:'/sort',state:{name : 'sunny' } })
this.props.location.state.name; // 接收参数
// 组件中使用this.props.history
import React, { Component } from 'react';
import { connect } from 'dva';
import {withRouter} from "react-router-dom";
class Test extends Component {
func(pro) {this.props.history.push({pathname: '/Demo', state: {my: 1111, my2: 2222}})} // 这个时候就可以访问到this.props.history了
render() {return (<><div onClick={()=>{this.func();}}></div></>);}
}
export default connect(()=>{return {};})(withRouter(Test));
// 另外一个组件中接收传过来的路由参数
class Demo extends Component {
componentDidMount() {this.props.location.state;} // 输出为{my: 1111, my2: 2222}。如果不是从上面的组件点击跳转的,那么this.props.location.state的值为undefined
}
export default Demo;
四、实例
// 然后我们新建两个页面,分别命名为“home”和“detail”。在页面中编写如下代码
// home.js
import React from 'react';
export default class Home extends React.Component {
render() {
return (
<div>
<a>去detail</a>
</div>
)
}
}
// detail.js
import React from 'react';
export default class Home extends React.Component {
render() {
return (
<div>
<a>回到home</a>
</div>
)
}
}
// Router.js
import React from 'react';
import {HashRouter, Route, Switch} from 'react-router-dom';
import Home from '../home';
import Detail from '../detail';
const BasicRoute = () => (
<HashRouter>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/detail" component={Detail}/>
</Switch>
</HashRouter>
);
export default BasicRoute;
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Router from './router/router';
ReactDOM.render(
<Router/>,
document.getElementById('root')
);