React--》ReactRouter5相关路由的使用讲解

目录

React路由

react-router-dom的安装与使用

Switch的使用以及模糊与严格匹配

嵌套路由

路由传参

编程式路由导航


现代的前端应用大多都是SPA(单页应用程序),也就是只有一个HTML页面的应用程序。因为它的用户体验更好、对服务器的压力更小,所以更受欢迎。为了有效的使用单个页面来管理原来多页面的功能,前端路由应运而生。

对SPA的理解

单页Web应用(single page web application,SPA)。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面,只会做页面的局部更新。数据都需要通过ajax请求获取,并在前端异步展现。

React路由

路由分为两种一种是后端路由:用来处理客户端提交的请求,用node举例,当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求返回响应数据;另一种是前端路由:用于展示页面内容,当浏览器的path变为/test时,当前路由组件就会变成Test组件。

前端路由的功能:让用户从一个视图(页面)导航到另一个视图(页面)

前端路由是一套映射规则,在React中,是URL路径与组件的对应关系

使用React路由简单来说,就是配置 路径组件 (配对)

react-router-dom的安装与使用

react-router是React官方维护的路由库,其主要有三种应用场景:web、native、any,顾名思义分别是web端、native端和任何场景都能使用的any,作为web前端开发人员,选择web、any都是可以的,但是web的端的针对性更强,所以推荐选择web,其第三方包名为:react-router-dom,与我们要操作浏览器的元素的想法不谋而合。

其官方网址:官方网址 ,因为React是外国人开发的框架,所以其网址内容都是英文,所以还是推荐一下中文文档:中文文档

注意:由于react-router-dom在2021年11月份升级到了6版本,此处讲解的是react-router-dom的5版本,关于最新的6版本会在下次文章中讲解,想要了解的可以订阅一下本专栏,博主将持续分享React知识:React专栏

终端执行如下命令进行安装 react-router-dom (5版本):

npm install react-router-dom@5

明确好界面中的导航区与展示区,导航区的a标签改为Link标签展示区写Route标签进行路径匹配

// 导航区
<Link to="/xxxxx">Demo</Link>
// 展示区
<Route path="/xxxx" component={Demo}>
import React, { Component } from 'react'
import {Link,Route} from "react-router-dom"
import Home from './components/Home/Home.jsx'
import About from './components/About/About.jsx'

export default class App extends Component {
  render() {
    return (
      <div>
        <div className='row ml-2'>
          <div className="col-xs-offset-2  col-xs-8">
            <div className='page-header'><h2>React Router Demo</h2></div>
          </div>
        </div>
        <div className='row ml-2'>
          <div className=" col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 导航区 */}
              <Link className="list-group-item" to="/home">Home</Link>
              <Link className="list-group-item" to="/about">About</Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="pandel-body">
                {/* 展示区 */}
                <Route path="/home" component={Home} />
                <Route path="/about" component={About} />
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

<App>的最外侧包裹了一个<BrowserRouter>或<HashRouter>,因为HashRouter的url地址上会一直出现 # 看着比较不舒服,所以BrowserRouter是比较符合人们的要求的,当然这里看个人选择

import React from 'react';
import ReactDOM from "react-dom";
import {BrowserRouter} from 'react-router-dom'
import App from './App'

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

路由组件与一般组件的区别

写法不同

        路由组件:<Route path="/xxxx" component={Demo}>

        一般组件:<Demo/>

存放位置不同

        路由组件:pages

        一般组件:components

接收到的props不同

        路由组件:接收到三个固定属性,分别是:history、location、match

        一般组件:组件标签传递了什么就能收到什么

BrowserRouter和HashRouter的区别

底层原理不一样

BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。

path表现形式不一样

BrowserRouter的路径中没有#,例如: localhost:3000/demo/test,HashRouter的路径包含#,例如: localhost:3000/#/demo/test。

刷新后对路由state参数的影响

(1).BrowserRouter没有任何影响,因为state保存在history对象中。

(2).HashRouter刷新后会导致路由state参数的丢失! ! !

备注: HashRouter可以用于解决一些路径错误相关的问题。

与普通的导航区标签Link不同,NavLink会给自己的标签添加一个激活的class属性,只要有点击激活该链接,class属性名就会出现,class属性名默认是 active ,可以搭配bootstrop使用,如果想更改class属性名可以使用activeClassName。具体如下:

当然使用NavLink也要先进行导入,导入之后就可以使用了。

为我们设置的class类名添加属性,因为就一个样式没有必要单独写在css文件,这里直接写在我们的index.html的style即可,如下:

我们发现,只要我们要设置NavLink的样式就得重复的写一遍activeClassName,有没有办法只需要写NavLink不同的地方比如to属性呢?答案是有的,需要我们将NavLink封装成一个一般组件,用我们封装好的组件来解决这个问题:

封装的组件内容如下,将相同的内容写在如下NavLink中,不同的内容通过父传子将内容传到自己封装的组件标签中,用展开运算符将所有传来的属性平铺到标签上,包括children属性:

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

export default class MyNavLink extends Component {
  render() {
    return (
      <NavLink activeClassName='zhangsan' className="list-group-item" {...this.props}/>
    )
  }
}

总结

NavLink可以实现路由链接的高亮,通过activeClassName指定样式名

标签体内容是一个特殊的属性标签

通过this.props.children可以获取标签体内容

Switch的使用以及模糊与严格匹配

不知道大家有没有考虑过这样一个问题,我们在展示区注册路由时,一个path路径引用多个组件,那么当前这个路径下的页面应该展示什么内容呢?如下:

可以看到当前的about路径下引用的两个组件的内容都出现了:

要知道,一般我们在进行路由注册组件的时候,一个路径匹配一个组件,为了避免这种情况,我们采用Switch进行规避:  

使用Switch之后,如果出现多个组件共用一个路径,默认只展示第一个,当然Switch也是要在路由库中导入才能使用:

解决完组件的混乱之后,我们在处理path路径的混乱,我们在注册路由的时候默认是模糊匹配,这是什么情况呢?如下:

我们在路由链接的to属性下,给出了具体的路径,而在展示区时,给出的路径仅仅的一点点,这种是能够达到模糊匹配的条件的,也是能在页面上展示出内容的

处理以上的情况,其它的情况都是不满足模糊匹配的条件的,如下几个例子举出:

严格匹配模式下,路由链接与路由占位符的path路径必须一一对应,出现一点路径问题都会匹配不上,如下:

总结

Switch的使用

通常情况下,path和component是一一对应关系。Switch可以提高路由匹配效率(单一匹配)。

严格匹配与模糊匹配

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

嵌套路由

嵌套路由很简单,在要嵌套的组件下,在写一份路由的匹配规则即可,如下:

import React, { Component } from 'react'
import MyNavLink from '../../components/MyNavLink/index.jsx'
import { Switch,Route } from 'react-router-dom'
import News from './News'
import Message from './Message'

export default class Home extends Component {
  render() {
    return (
      <div>
        <h2>我是Home内容</h2>
        <div>
          <ul className='nav nav-tabs'>
            <li>
              <MyNavLink to='/home/news'>News</MyNavLink>
            </li>
            <li>
              <MyNavLink to='/home/message'>Message</MyNavLink>
            </li>
          </ul>
        </div>
        {/* 注册路由——展示区 */}
        <Switch>
          <Route path="/home/news" component={News} />
          <Route path="/home/message" component={Message} />
        </Switch>
      </div>
    )
  }
}

如果重定向路由,可以使用Redirect,其一般写在所有路由注册的最下方。当所有路由都无法匹配时,跳转到Redirect指定的路由。

总结

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

路由传参

向路由传递参数有以下三种方式:

params参数

将获取的参数id和title遍历之后依次传入嵌套子组件,路由链接携带参数注册路由声明接收

通过解构赋值的办法将传递过来的参数渲染到页面上

match里面就存放着我们传递的数据:

完整代码:

import React, { Component } from 'react'
import { Link,Route } from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component {
  state = {
    messageArr:[
      {id:'01',title:'消息1'},
      {id:'02',title:'消息2'},
      {id:'03',title:'消息3'},
    ]
  }
  render() {
    const {messageArr} = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((messageObj)=>{
              return <li key={messageObj.id}>
                {/* 向路由组件传递props参数 */}
                <Link to={`/home/message/detail/${messageObj.id}/${messageObj.title}`}>{messageObj.title}</Link>
              </li>
            })
          }
        </ul>
        <hr />
        {/* 声明接收params参数 */}
        <Route path="/home/message/detail/:id/:title" component={Detail} />
      </div>
    )
  }
}
import React, { Component } from 'react'

const DetailData = [
  {id:'01',content:'111'},
  {id:'02',content:'222'},
  {id:'03',content:'333'},
]
export default class Detail extends Component {
  render() {
    // 接收params参数
    const {id,title} = this.props.match.params 
    const findResult = DetailData.find((detailObj)=>{
      return detailObj.id === id
    })
    return (
      <ul>
        <li>ID:{id}</li>
        <li>TITLE:{title}</li>
        <li>CONTENT:{findResult.content}</li>
      </ul>
    )
  }
}

search参数

search传递参数发送数据十分容易,但是接收到数据有点小繁琐,如下:

我们在传递参数的时候,通过如下类似query参数的形式进行传参,路由声明接收时,无需更改代码,正常注册路由即可,可见search传递参数极为方便 。

但是当我们在子组件去接收props参数时,有点小烦,因为search传递过来的并不是对象的键值对形式,而是一个字符串,需要我们对传递过来的东西进行一定的修改:

不废话直接告诉大家,react本身就有一个qs库,可以帮助我们将类似urlencode的编码格式转成对象格式,如:name=zs&age=18 转成 {name:'zx',age:18} ,使用方法和json类似。接收的参数是在location里面,获取到的search是urlencoded编码字符串,需要借助qs进行解析:

接下直接使用slice去掉第一个?就可以了,废话不多说,完整代码如下:

import React, { Component } from 'react'
import qs from 'qs'

const DetailData = [
  {id:'01',content:'111'},
  {id:'02',content:'222'},
  {id:'03',content:'333'},
]
export default class Detail extends Component {
  render() {
    const {search} = this.props.location
    // 接收search参数
    const {id,title} = qs.parse(search.slice(1))
    const findResult = DetailData.find((detailObj)=>{
      return detailObj.id === id
    })
    return (
      <ul>
        <li>ID:{id}</li>
        <li>TITLE:{title}</li>
        <li>CONTENT:{findResult.content}</li>
      </ul>
    )
  }
}

state参数

state与我们react中初始化状态的state无关,只是名字相同而已,state传递参数也是最简单的:

state传递参数,路径和参数都放在一个对象里面,state里面存放我们要传递的参数:

接收参数也很简单,一个解构赋值即可,如下:

虽然state传递参数很简单,但是有个问题就是,在我们切换路由的时候,浏览器的url并不会发送任何变化,所以是否使用state还是看个人选择:

总结

这三种形式的传参,项目中都用的很多,都应该尽量掌握,根据具体需求,parmas显示路径相对清爽、search强调参数清楚明了、state隐藏信息安全保障,今后在项目中还是根据大家的需求,具体情况具体方法。

编程式路由导航

浏览器默认情况下是开启push模式的,也就是你在当前页面点击下一个页面,点击浏览器的回退按钮能够回退到你上一次浏览的页面,而开启replace模式后,会替换掉你当前浏览的页面,也就是说,你点击了开启replace模式的网页的话,点击回退会回退到上上个页面,因为上个页面已经被你开启replace模式的网页替换掉了,开启replace方法如下:Link标签添加replace属性即可。

如果想通过按钮的形式来实现编程式导航的跳转,可以调用history:

history是 React路由提供的,用于获取浏览器历史记录的相关信息push(path):

跳转到某个页面,参数path表示要跳转的路径
go(n)∶前进或后退到某个页面,参数n表示前进或后退页面数量(比如:-1表示后退到上一页)

举个简单的例子,给一个定时器,2秒过后,自动跳转到另一个路由:

那么问题来了,如果我想给一般组件也设置一个回退按钮能实现吗?注意:只要路由组件才有其特殊的三个属性的API,一般组件是不能调用路由组件中的history的,怎么办?

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

withRouter的返回值是一个新组件。

猜你喜欢

转载自blog.csdn.net/qq_53123067/article/details/127001743
今日推荐