安装 : npm install react-router-dom

定义路由规则

src/router/index.js

  1. import React, { Component } from 'react'
  2. import { HashRouter as Router,Redirect,Route,Switch} from 'react-router-dom'
  3. import Films from '../views/Films' //...一堆组件引入
  4. function isAuth(){
  5. return localStorage.getItem("token")
  6. }
  7. export default class IndexRouter extends Component {
  8. render() {
  9. return (
  10. <Router>
  11. {this.props.children}
  12. <Switch>
  13. <Route path="/films" component={Films} />
  14. <Route path="/cinemas" component={Cinemas} />
  15. <Route path="/center" component={Center} />
  16. {/* 默认路由 */}
  17. <Redirect from="/" to="/home" exact/>
  18. {/* 404 这个要放到最后(当匹配不到时) */}
  19. <Route component={NotFound}/>
  20. </Switch>
  21. </Router>
  22. )
  23. }
  24. }

Switch 渲染第一个匹配

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

{/同时展示Home Test两个组件/}

{/只展示Home组件/}

<a name="Mxuip"></a> ### exact - 路由的严格匹配与模糊匹配 1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)<br />2.开启严格匹配:`<Route exact path="/about" component={About}/>`<br />3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由 <a name="E2y0f"></a> ### Redirect(路由重定向)的使用 1. 访问[http://localhost:3000](http://localhost:3000/about) 会跳到 [http://localhost:3000/about](http://localhost:3000/about) 1. 访问不存在的也会调到[http://localhost:3000/about](http://localhost:3000/about)jsx import {Route ,Redirect} from ‘react-router-dom’ {/ 1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由 2.具体编码: /} <a name="TEhBv"></a> ## 导入路由 > app.js导入使用jsx import React, { Component } from ‘react’ import Router from ‘./router/IndexRouter’ import Tabbar from ‘./components/Tabbar’ export default class App extends Component { render() { return (
{/ 其他的内容 /} {/ 被Router组件包裹的组件才能使用路由 /}
) } } <a name="l1zGU"></a> ## NavLink声明式导航 > Tabbar组件jsx import { NavLink } from ‘react-router-dom’ {/ Navlink会被渲染为a标签/} 电影 <a name="PkCuL"></a> ### 禁用Link > 想要禁用Link,开发阶段使用 `BrowserRouter` 可以使用:jsx xxx > 但如果上线使用 `HashRouter` ,就会跳到404页面,因此需要补充:jsx xxx // App.less中补上: a[disabled] { pointer-events: none; } <a name="bsDqM"></a> ## 编程式路由导航jsx //类组件 class Home extends Component{ this.props.history.push(/filmsorder) } //函数组件 function Center(props) { props.history.push(/filmsorder) } //hooks函数组件 import {useHistory} from ‘react-router-dom’ function Center(props) { const history =useHistory() history.push(/filmsorder) } //其他路由方法 -this.prosp.history.push() -this.prosp.history.replace() -this.prosp.history.goBack() -后退 -this.prosp.history.goForward() -前进 -this.prosp.history.go() -参数n,可以是负数 <a name="xFQK2"></a> ## 嵌套路由 <a name="XZw9i"></a> ### 写法一 > 将嵌套路由写到父路由中jsx import React, { Component } from ‘react’ import Nowplaying from ‘./films/Nowplaying’ import {NavLink, Redirect, Route, Switch} from ‘react-router-dom’ //Films的路由规则 已经定义过 export default class Films extends Component { render() { return (
//… {/嵌套路由 必须定义在父组件中 /}
) } } <a name="E0Q5d"></a> ### 写法二 由写法一可延伸为以下写法 可以不用写到父组件中 > router/index.js 定义路由规则 ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1652675621424-54399a93-1211-4e75-9a44-b0a24e7d0552.png#clientId=ucb866e54-8019-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=339&id=ud84d2728&margin=%5Bobject%20Object%5D&name=image.png&originHeight=559&originWidth=1143&originalType=binary&ratio=1&rotation=0&showTitle=false&size=201750&status=done&style=none&taskId=ubeb8584a-5f98-414e-88d0-e5ed42de30c&title=&width=692.727232688717) > 父组件 这里是app组件, 利用this.props.children(react.creatElement将children渲染为标签中间的内容) > 按照vue的话可以理解为一个<view-router> ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1652675731032-31433890-43a2-4ea4-b139-d12dd588a5da.png#clientId=ucb866e54-8019-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=239&id=u6a726143&margin=%5Bobject%20Object%5D&name=image.png&originHeight=395&originWidth=709&originalType=binary&ratio=1&rotation=0&showTitle=false&size=84958&status=done&style=none&taskId=uaef745b1-a6ef-4f94-9fce-107b3275269&title=&width=429.69694486115515) <a name="r3XFv"></a> ## 路由传参 <a name="WJrDr"></a> ### 1. paramsjsx {/ /detail/1111 定义规则 /} //跳转传参 props.history.push(/detail/${id}) //或xx //获取 export default function Detail(props) { console.log(props.match.params.myid) } <a name="fgjKj"></a> ### 2. queryjsx Home this.props.history.push({ pathname : ‘/user’ ,query : { day: ‘Friday’} }) this.props.location.query.day <a name="m9tpW"></a> ### 3. statejsx Home this.props.history.push({ pathname:’/user’,state:{day : ‘Friday’ } }) this.props.location.state.day <a name="r5Kfj"></a> ## 路由拦截(守卫) <a name="f2lYi"></a> ### 函数形式 > src/router/index.jsjsx import React, { Component } from ‘react’ import { HashRouter as Router,Redirect,Route,Switch} from ‘react-router-dom’ //…一堆组件引入 //判断是否登录 function isAuth(){ return localStorage.getItem(“token”) } export default class IndexRouter extends Component { render() { return ( {/ 路由拦截 没登录去login组件/} { return isAuth()?
: }}/>
  </Router>
)

} }

<a name="UDOc1"></a>
### 高阶组件形式
> components/AuthRoute/index.js

```jsx
// 1. 判断token是否存在
// 2. 如果存在 直接正常渲染
// 3. 如果不存在 重定向到登录路由

// 高阶组件:把一个组件当成另外一个组件的参数传入 然后通过一定的判断 返回新的组件
import { getToken } from '@/utils'
import { Navigate } from 'react-router-dom'

function AuthRoute ({ children }) {
  const isToken = getToken()
  if (isToken) {
    return <>{children}</>
  } else {
    return <Navigate to="/login" replace />
  }
}

// <AuthComponent> <Layout/> </AuthComponent>
// 登录:<><Layout/></>
// 非登录:<Navigate to="/login" replace />

export {
  AuthRoute
}

src/router/index.js

import { AuthRoute } from './components/AuthRoute'
<Routes>
  {/* 需要鉴权的路由 */}
  <Route path="/" element={
      <AuthRoute>
        <Layout />
      </AuthRoute>
    }>
  </Route>
  {/* 不需要鉴权的路由 */}
  <Route path='/login' element={<Login />} />
</Routes>

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>
    

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

  3. withRouter可以加工一般组件,让一般组件具备路由组件所特有的API

  4. withRouter的返回值是一个新组件 ```jsx import React, { Component } from ‘react’ import {withRouter} from ‘react-router-dom’

class Header extends Component { go = ()=>{ this.props.history.go(-2) }

render() {
    console.log('Header组件收到的props是',this.props);
    return (
        <div className="page-header">
            <button onClick={this.go}>go</button>
        </div>
    )
}

} //props 具有history是可以使用路由功能 export default withRouter(Header) ```

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可以用于解决一些路径错误相关的问题。