2022-03-12 学习记录--React-路由(6.0版本)

什么是路由?

  1. 一个路由就是一个映射关系(key:value);
  2. key路径value可能是 functioncomponent

React里面,对于路由,我们需要用到react-router-dom,但是,react脚手架里面并没有帮我们去下载react-router-dom,所以,我们需要自己安装react-router-dom

一、react-router的官方网站

苦于找不到好的中文文档?推荐一个很厉害的网站:印记中文。

第一步、进入印记中文 或 百度搜索印记中文

第二步、见下图在这里插入图片描述第三步、进入react-router的官方网站后,见下图在这里插入图片描述

二、react-router-dom的安装与使用

1、安装方法:yarn add react-router-dom 或者 npm install react-router-dom【注意:yarnnpm混着用,及其容易造成包的丢失】
在这里插入图片描述
2、使用路由库

举个例子吧~👇

【注意】下面给出的案例中的react-router-dom是v6(6.2.2版本) 🤞

1、实现效果:

  1. 一进入页面,就展示组件About的内容,About盒子显示高亮效果;
  2. 点击About盒子,就把组件About展示出来,About盒子显示高亮效果;
  3. 点击Home盒子,就把组件Home展示出来,Home盒子显示高亮效果。
    在这里插入图片描述

2、思维分析:假如先忽略盒子的高亮效果(粉色背景,白色字体),则需要使用到 路由链接 Link (相当于a标签)和 注册路由Route

  1. 路由链接 Link:如果你点击了About盒子,你的路径就变成/about;如果你点击了Home盒子,你的路径就变成/home
  2. 注册路由Route:如果你的路径变成了/about,就把组件About展示出来;如果你的路径变成了/home,就把组件Home展示出来。
  3. 通过路径变化这个中间变量,实现:点击About盒子,就把组件About展示出来;点击Home盒子,就把组件Home展示出来。
    在这里插入图片描述

1)、路由库的引入和使用

它这个是需要什么则引入什么,例如:路由链接 LinkLink要放在Router里面】、注册路由RouteRoute要放在Routes里面,Routes要放在Router里面】

Router分为两种:BrowserRouterHashRouter

  • BrowserRouter:url地址里面没有#符,如:localhost:3000
  • HashRouter:url地址里面会有#符,#符后边的内容(哈希值)都不会作为资源发送给服务器,如:localhost:3000/#/
BrowserRouter与HashRouter的区别
			1.底层原理不一样:
						BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
						HashRouter使用的是URL的哈希值。
			2.path表现形式不一样
						BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
						HashRouter的路径包含#,例如:localhost:3000/#/demo/test
			3.刷新后对路由state参数的影响
						(1).BrowserRouter没有任何影响,因为state保存在history对象中。
						(2).HashRouter刷新后会导致路由state参数的丢失!!!
			4.备注:HashRouter可以用于解决一些路径错误相关的问题。

First、 路由链接 LinkLink要放在Router里面】
在这里插入图片描述
对应代码

{/* 编写路由链接:在React中靠路由链接实现切换组件 —— Link要放在Router里面 */}
<BrowserRouter>
    <Link className="list-group-item" to="/about">About</Link>
    <Link className="list-group-item" to="/home">Home</Link>
</BrowserRouter>

结果

1、页面一进来时,url地址栏为初始地址,如:localhost:3000
2、当点击下方的About盒子后,url地址栏在初始地址上加了个/about,如:localhost:3000/about
3、当点击下方的Home盒子后,url地址栏在初始地址上加了个/home,如:localhost:3000/home
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

Second、 注册路由RouteRoute要放在Routes里面,Routes要放在Router里面】
在这里插入图片描述
对应代码

{/* 注册路由 —— Route要放在Routes里面,Routes要放在Router里面 */}
<BrowserRouter>
    <Routes>
              
    {/* 旧版写法 */}
    {/*
       <Route path="/" component={About}/>
       <Route path="/about" component={About}/>
       <Route path="/home" component={Home}/> 
    */}
    {/* 新版写法 */}
       <Route path="/" element={<About />}/>
       <Route path="/about" element={<About />}/>
       <Route path="/home" element={<Home />}/>
                  
     </Routes>
</BrowserRouter>

到这里,小萝卜儿们肯定觉得已经可以达到我们需要实现的效果了吧,But,当我们运行代码后,点击盒子切换时,对应组件内容并没有相应变化也~ 什么?怎么会这亚子,好奇宝宝👶又开始挠自己滴小脑袋咯😢

在这里插入图片描述

就不藏着掖着啦~造成上面无效的原因就是:上面代码中使用了两个路由器BrowserRouter进行包裹,这两个路由器相互之间并没有联系:路由器A变化了 并没有通知路由器B路由器B变化了 并没有通知路由器A,它们两个之间没有进行数据的沟通。So,针对上面代码,不能链接路由Link里面包了一个路由器,注册路由Route里面再包一个路由器,而应该整个应用都由一个路由器进行包裹,而不是多个

这时爱动脑筋的小萝卜儿🥕们心想:在这个页面里面,把那两个路由器往外扩展 变成 一个路由器就好啦(如下图)
在这里插入图片描述

But,这样滴话,假如往后新增页面代码,就又需要调整<BrowserRouter></BrowserRouter>的位置,会比较麻烦哦。
So,我们可以直接在index.js里面将整个App组件包裹住哦(如下图)。
在这里插入图片描述
注意】要回去App.jsx里面将引入BrowserRouter相关的代码删除掉哟

2)、未实现盒子的高亮效果时,App.jsx的代码

import React, { Component } from 'react'
import {Link, Routes ,Route} from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header"><h2>React Router Demo</h2></div>
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">

              {/* 原生html中,靠a标签跳转到不同的页面 */}
              {/* <a href="./about.html" className="list-group-item"></a>
              <a href="./home.html" className="list-group-item active"></a> */}

              {/* 编写路由链接:在React中靠路由链接实现切换组件 —— Link要放在Router里面 */}
              <Link className="list-group-item" to="/about">About</Link>
              <Link className="list-group-item" to="/home">Home</Link>

            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">

                {/* 注册路由 —— Route要放在Routes里面,Routes要放在Router里面 */}
                <Routes>

                  {/* 旧版写法 */}
                  {/*
                    <Route path="/" component={About}/>
                    <Route path="/about" component={About}/>
                    <Route path="/home" component={Home}/> 
                  */}
                  {/* 新版写法 */}
                    <Route path="/" element={<About />}/>
                    <Route path="/about" element={<About />}/>
                    <Route path="/home" element={<Home />}/>

                </Routes>

              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}
  • 对于路由链接的高亮效果,该如何实现呢?这个就需要用到NavLink标签啦~(替换掉原先使用的Link标签)
    • NavLink后,就是点谁就给谁追加一个样式的类名active
    • 假如你不想用默认的类名active的样式,那你就可以通过activeClassName指定样式名,But注意:6.0版本官方已经不再支持activeClassName这种写法了,换成动态设置className了。

比如:实现点谁就给谁追加样式类名selected

{/* 编写路由链接:在React中靠路由链接实现切换组件 —— Link要放在Router里面 */}
{/* <Link className="list-group-item" to="/about">About</Link>
    <Link className="list-group-item" to="/home">Home</Link> */}
              
{/* 编写路由链接(并实现高亮效果):在React中靠路由链接实现切换组件 —— NavLink要放在Router里面 */}
{/* 旧版写法 */}
{/* <NavLink activeClassName="selected" className="list-group-item" to="/about">About</NavLink>
    <NavLink activeClassName="selected" className="list-group-item" to="/home">Home</NavLink> */}
{/* 新版v6写法 */}
	<NavLink className={({ isActive }) => "list-group-item" + (isActive ? " selected" : "")} to="/about">About</NavLink>
    <NavLink className={({ isActive }) => "list-group-item" + (isActive ? " selected" : "")} to="/home">Home</NavLink>

当当当,这样就可以实现高亮效果啦~😁

总结:路由链接(相当于a标签): 不需要高亮效果用Link,需要高亮效果用NavLink

But,通过观察🤔可以发现,上面的写法中,两个NavLink有共同部分:className={({ isActive }) => "list-group-item" + (isActive ? " selected" : "")};在需要出现多个NavLink的情况下,岂不是就显得比较繁琐了;假如我们可以只展示它们之间不同的部分,岂不乐乎😉~ 所以 我们最好对路由组件进行封装

  • 封装一个一般组件MyNavLink
    一般组件MyNavLink里的index.jsx待完善):在这里插入图片描述
    App.jsx
    在这里插入图片描述
  • 但是按照上面写法的话,假如需要传很多数据,这样一个一个写的话,就会显得代码冗余咯,比如:
    • <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink>还需要传入abc滴话,岂不是在一般组件MyNavLink里就需要通过props接收到toabc的值,然后按照to={to} a={a} b={b} c={c}这样的写法传到组件MyNavLink里去,那有没有什么简洁的好办法呢?🤔
    • 当然有哟,那就是{...this.props}🤞:在组件MyNavLink里,不用接收props里的值,直接用{...this.props}替换掉to={to} a={a} b={b} c={c}就好啦;
    • 通过{...this.props}获取到props里的值,直接渲染上去就可以啦,不管传了好多个值,不用再一个一个写了,简洁了不少。
  • 这时爱动脑筋的小萝卜儿们🥕肯定想问:那title还不是要接收的嘛,不然<NavLink></NavLink>之间的标签体怎么展示呢?
    • 答案是:连title都不需要接收哟。这里有个新知识点啦,请往下看👇
      • 标签体内容是一个特殊的标签属性,也可通过props获取到(通过this.props.children);
        双标签的标签体 和 单标签的标签属性children值 是一样滴效果。
      • 比如:<MyNavLink to="/about">About</MyNavLink ><MyNavLink to="/about" children="About"/>是一个意思
        在这里插入图片描述
        打印this.props👇
        在这里插入图片描述
  • 所以直接在单标签<NavLink/>里写入{...this.props}就相当于给其加入了标签体About和Home
  • 那么 一般组件MyNavLink里的index.jsx最终代码):在这里插入图片描述

到这里,关于盒子的高亮问题,还有一个细节就是:url地址为'/'时,我让它默认展示的是About组件的内容,这没错,但是细心的小萝卜儿们🥕就会发现,为什么页面一进来,About盒子没有出现高亮效果呢?那。。。该如何实现呢?

  • 首先回答第一个问题——为什么页面一进来,About盒子没有出现高亮效果呢?
    • 因为上面代码中,我们是通过<Route path="/" element={<About />}/>来实现:url地址为'/'时,让其展示About组件的内容,但是我们并没有针对url地址为'/'时的盒子,自然就不能出现高亮效果咯~
  • 那。。。第二个问题——该如何实现呢?
    这里我们就需要再学习一个新知识点啦:Redirect(重定向)
    • Redirect(重定向):若url地址path=""的都没匹配上,则去Redirect指向的路径。(一般写在所有路由注册的最下方) 【注意:在v6已被移除,在v6中需引入Navigate标签来替代之前Redirect的重定向操作
    • 比如: <Route path="*" element={<Navigate to="/about"/>}/>

本案例App.jsx的最终代码

import React, { Component } from 'react'
import {Routes ,Route , Navigate} from 'react-router-dom'

// 引入路由组件
import Home from './pages/Home'
import About from './pages/About'

// 引入一般组件
import Header from './components/Header'
import MyNavLink from './components/Header/MyNavLink'

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">

              {/* 原生html中,靠a标签跳转到不同的页面 */}
              {/* <a href="./about.html" className="list-group-item"></a>
              <a href="./home.html" className="list-group-item active"></a> */}

              {/* 编写路由链接:在React中靠路由链接实现切换组件 —— Link要放在Router里面 */}
              {/* <Link className="list-group-item" to="/about">About</Link>
              <Link className="list-group-item" to="/home">Home</Link> */}
              
              {/* 编写路由链接(并实现高亮效果):在React中靠路由链接实现切换组件 —— NavLink要放在Router里面 */}
              {/* 旧版写法 */}
              {/* <NavLink activeClassName="selected" className="list-group-item" to="/about">About</NavLink>
              <NavLink activeClassName="selected" className="list-group-item" to="/home">Home</NavLink> */}
              {/* 新版v6写法 */}
              {/* <NavLink className={({ isActive }) => "list-group-item" + (isActive ? " selected" : "")} to="/about">About</NavLink>
              <NavLink className={({ isActive }) => "list-group-item" + (isActive ? " selected" : "")} to="/home">Home</NavLink> */}

              {/* 上面写法太繁琐,所以采用封装组件的方法 */}
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink>

            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">

                {/* 注册路由 —— Route要放在Routes里面,Routes要放在Router里面 */}

                  {/* 旧版写法 exact是开启严格模式,默认是false(非严格匹配模式)【注意:严格匹配不能随便开启,要 因为这个严格匹配/模糊匹配 产生问题,才开启】 */}
                  {/*
                  <Switch>
                    <Redirect to="/about"/>
                    <Route exact path="/" component={About}/>
                    <Route path="/about" component={About}/>
                    <Route path="/home" component={Home}/> 
                  </Switch>  
                  */}
                  
                  {/* 新版写法 */}
                  <Routes>

                    {/* Redirect(重定向):若都没匹配上,则去Redirect指向的路径 [在v6已被移除,在v6中需引入Navigate标签来替代之前Redirect的重定向操作]*/}
                    {/* 采用Navigate实现重定向,可以使url地址为'/'时,About盒子产生高亮效果 */}
                    <Route path="*" element={<Navigate to="/about"/>}/>
                    {/* 采用路由方式,不可以使url地址为'/'时,About盒子产生高亮效果 */}
                    {/* <Route path="/" element={<About />}/> */}
                    <Route path="/about" element={<About />}/>
                    <Route path="/home" element={<Home />}/>

                  </Routes>

              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

3)、案例中遇到的报错总结

Error1: 【注册路由Route
在这里插入图片描述
解决方法:注意旧版和新版的写法哟~改成新版写法就可以啦【在v6中,Switch标签替换成了Routes标签、element代替了component

{/* 注册路由 —— Route要放在Routes里面,Routes要放在Router里面 */}
<Routes>

    {/* 旧版写法 */}
    {/*
      <Route path="/" component={About}/>
      <Route path="/about" component={About}/>
      <Route path="/home" component={Home}/> 
    */}
    {/* 新版写法 */}
      <Route path="/" element={<About />}/>
      <Route path="/about" element={<About />}/>
      <Route path="/home" element={<Home />}/>

</Routes>

Error2: 【注册路由Route

No routes matched location "/"

解决方法:添加一个 “/” 路径的路由,就可以啦

错误写法 ❌
在这里插入图片描述
正确写法一 ✔
在这里插入图片描述
正确写法二(重定向) ✔

{/* 新版写法——解决方法2(重定向) */}
<Route path="/about" element={<About />}/>
<Route path="/home" element={<Home />}/>
<Route path="*" element={<Navigate to="/about"/>}/>

在这里插入图片描述

These are bilibili尚硅谷React学习视频的 学习笔记~

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小呀小萝卜儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值