React Router

这东西好像和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')
);
上一篇:React中使用PropTypes进行类型检查


下一篇:56