react-router-dom@5

安装 : npm install react-router-dom

路由的基本使用

  1. import {Route , Link} from 'react-router-dom'
  2. {/* 路由链接 */}
  3. <Link to="/xxxxx">Demo</Link>
  4. {/* 路由展示 */}
  5. <Route path='/xxxx' component={Demo}/>

的最外侧包裹了一个

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

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

路由组件与一般组件

        1.写法不同:
                    一般组件:<Demo/>
                    路由组件:<Route path="/demo" component={Demo}/>
        2.存放位置不同:
                    一般组件:components
                    路由组件:pages
        3.接收到的props不同:
                    一般组件:写组件标签时传递了什么,就能收到什么
                    路由组件:接收到三个固定的属性
                                        history:
                                                    go: ƒ go(n)
                                                    goBack: ƒ goBack()
                                                    goForward: ƒ goForward()
                                                    push: ƒ push(path, state)
                                                    replace: ƒ replace(path, state)
                                        location:
                                                    pathname: "/about"
                                                    search: ""
                                                    state: undefined
                                        match:
                                                    params: {}
                                                    path: "/about"
                                                    url: "/about"

NavLink 与 封装NavLink

  1. 默认高亮: active
  2. NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
import { NavLink} from 'react-router-dom';

<NavLink activeClassName="Dan" to="/about">About</NavLink>

封装一个NavLink组件 , MyNavLink

import React,{Component} from 'react';
import {NavLink} from 'react-router-dom'

export default class MyNavLink extends Component{
    render(){
        return(
          {/*{...this.props} react自动生成一个children的key作为路由链接名*/}
            <NavLink activeClassName="Dan" className="list-group-item" {...this.props}></NavLink>
        )
    }
}

{/*使用*/}
<MyNavLink to="/about">About</MyNavLink>

Switch

  1. 通常情况下,path和component是一一对应的关系。
  2. Switch可以提高路由匹配效率(单一匹配)。react 默认会一直往下找Route匹配 , 添加了Switch则不会匹配下一个 /home
import {Route ,Switch} from 'react-router-dom';

{/*同时展示Home Test两个组件*/}
<Route path="/home" component={Home}></Route>
<Route path="/home" component={Test}></Route>

{/*只展示Home组件*/}
<Switch>
  <Route path="/home" component={Home}></Route>
  <Route path="/home" component={Test}></Route>
</Switch>

解决多级路径刷新页面样式丢失的问题

最新脚手架没发现该问题
PS:
localhost:3000 就是脚手架中webpack的devserve提供的内置服务器 其根地址就是public 即localhost:3000,
如果请求一个不存在的地址 react默认返回public下的index.html

1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
3.使用HashRouter

exact - 路由的严格匹配与模糊匹配

1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
2.开启严格匹配:<Route exact={true} path="/about" component={About}/>
3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

不开启时这样依然能匹配到

<MyNavLink to="/dan/home/a/b">Home</MyNavLink>
<Route exact path="/dan/home" component={Home}></Route>

默认路由

image.png

{/* 默认路由匹配时,跳转到 /home 实现路由重定向到首页 */}
<Route path="/" exact render={() => <Redirect to="/home" />} />

Redirect(路由重定向)的使用

  1. 访问http://localhost:3000 会跳到 http://localhost:3000/about
  2. 访问不存在的也会调到http://localhost:3000/about
import {Route ,Redirect} from 'react-router-dom'
{/*
  1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
  2.具体编码:
*/}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>

lazyLoad - 按需加载 -v16.6以上

run build时会单独生成js和css文件,点击路由导航时才会在newwork加载

  1. import {lazy,Suspense} from 'react'
  2. <Suspense fallback={}>

    import React , {Component,lazy,Suspense} from 'react'
    //1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
     const Login = lazy(()=>import('@/pages/Login'))
    
     //2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
    {/* <Suspense fallback={<Loading/>}> */} //可以导入一个Loading组件作为fallback
     <Suspense fallback={<h1>loading.....</h1>}>
     <Switch>
       <Route path="/xxx" component={Xxxx}/>
       <Redirect to="/login"/>
     </Switch>
    </Suspense>
    

嵌套路由

  1. 注册子路由时要写上父路由的path值
  2. 路由的匹配是按照注册路由的顺序进行的

    {/*在home路由组件中 访问子路由组件detail*/}
    <Link to="/home/detail">Detail</Link>
    <Route path="/home/detail" component={Detail}></Route>
    
  3. 当父路由params传参,不带上父的参数会找不到路由地址 ```jsx {/父路由/} Home

{/子路由/}

Detail

<a name="aeea3047"></a>
## 向路由组件传递参数

1. params参数
   1. 路由链接(携带参数):`<Link to='/demo/test/tom/18'}>详情</Link>`
   1. 注册路由(声明接收):`<Route path="/demo/test/:name/:age" component={Test}/>`
   1. 接收参数:`this.props.match.params`
2. search参数
   1. 路由链接(携带参
   1. 数):`<Link to='/demo/test?name=tom&age=18'}>详情</Link>`
   1. 注册路由(无需声明,正常注册即可):`<Route path="/demo/test" component={Test}/>`
   1. 接收参数:`this.props.location.search`

备注:获取到的search是urlencoded编码字符串,需要借助querystring解析

      1. `import qs from 'querystring'`
      1. `const {search} = this.props.location `
      1. `const {name,age} = qs.parse(search.slice(1))`
3. state参数
   1. 路由链接(携带参数):`<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>`
   1. 注册路由(无需声明,正常注册即可):`<Route path="/demo/test" component={Test}/>`
   1. 接收参数:`this.props.location.state`

备注:刷新也可以保留住参数

```jsx
{/*params*/}
<MyNavLink to="/home/dan/18">Home</MyNavLink>
<Route path="/home/:name/:age" component={Home}></Route>
console.log(this.props.match.params); //{name: "dan", age: "18"}

{/*search*/}
<MyNavLink to="/home/?name='dan'&age=18">Home</MyNavLink>
<Route path="/home" component={Home}></Route>
console.log(this.props.location.search); //?name='dan'&age=18

{/*state*/}
<MyNavLink to= {{pathname:"/home" , state:{name:'dan',age:'18'}} }>Home</MyNavLink>
<Route path="/home" component={Home}></Route>
console.log(this.props.location.state);//{name: "dan", age: "18"}

编程式路由导航

借助this.prosp.history对象上的API对操作路由跳转、前进、后退
-this.prosp.history.push()
-this.prosp.history.replace()
-this.prosp.history.goBack() -后退
-this.prosp.history.goForward() -前进
-this.prosp.history.go() -参数n,可以是负数

componentDidMount(){
  setTimeout(()=>{
  this.props.history.push('/home/message')
  this.props.history.goBack();
  this.props.history.goForward();
  },2000)
}

withRouter 将非路由组件转为路由组件

  1. withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
  2. withRouter的返回值是一个新组件
  3. export default withRouter(Header) ```jsx import React, { Component } from ‘react’ import {withRouter} from ‘react-router-dom’

class Header extends Component {

back = ()=>{
    this.props.history.goBack()
}

forward = ()=>{
    this.props.history.goForward()
}

go = ()=>{
    this.props.history.go(-2)
}

render() {
    console.log('Header组件收到的props是',this.props);
    return (
        <div className="page-header">
            <h2>React Router Demo</h2>
            <button onClick={this.back}>回退</button>&nbsp;
            <button onClick={this.forward}>前进</button>&nbsp;
            <button onClick={this.go}>go</button>
        </div>
    )
}

}

export default withRouter(Header)

<a name="9acfe9b2"></a>
## BrowserRouter与HashRouter的区别

1.底层原理不一样: (1).BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。 ps:this.props中的history是react封装的 不是H5中的 (2).HashRouter使用的是URL的哈希值。相当于锚点 不会发给服务器但又能形成历史记录,所以可以使用history的API实现前进后退。 2.path表现形式不一样 BrowserRouter的路径中没有#,例如:localhost:3000/demo/test HashRouter的路径包含#,例如:localhost:3000/#/demo/test 3.刷新后对路由state参数的影响 (1).BrowserRouter没有任何影响,因为state保存在history对象中。 (2).HashRouter刷新后会导致路由state参数的丢失!!! 4.备注:HashRouter可以用于解决一些路径错误相关的问题。 ```