【React四】 React-router-dom【关于React18及React16的路由使用对比】

对照代码查看笔记: 代码详情

  • 有详细的ReadMe文档

四、 路由

单页面 多组件: 整个应用只有一个完整的页面,局部更新

4-1

4-1-1

  1. 路由:
    • 一个映射关系(key:value)
    • key为路径,value可能是function或components
  2. 后端路由:
    • value是function,用来处理客户端提交的请求
    • 注册路由:router.get(path,function(req,res))
    • 工作过程:当node接收一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据
  3. 前端路由:
    • 浏览器端路由:value是component,用来展示页面内容
    • 注册路由:<Route path="/test" component={Test}>
    • 工作过程:当浏览器的path变为/test时,当前路由组件就会变为Test组件

4-2 react-router-dom

印记中文

4-2-1 插件库

    • react的一个插件库
    • 专门用来实现一个SPA应用
    • 基于react的项目基本都会用到此库
  1. yarn add react-router-dom

4-2-2 内置组件:

一、

  1. <BroswerRouter>
  2. <HashRouter>
  3. <Route>
  4. <Redirect>
  5. <Link>
  6. <NavLink>
  7. <Switch>

二、

  1. history对象
  2. match对象
  3. withRouter函数

4-2-3 路由的基本使用

react-router-dom@6

react-router-dom@5

  1. 明确好界面中的导航区、展示区

  2. 导航区的a标签改为Link标签

    <Link to="/xxx">Demo</Link>

  3. 展示区写Route标签进行路径的匹配

    <Route path="/xxx" component={Demo}>

  4. <App>的最外侧包裹了<HashRouter><BrowserRouter>

4-2-4 路由组件和一般组件的区别

  • 路由组件在pages中
  • 一般组件在components中
4-2-4-1 路由组件
  1. About组件

    import React, { Component } from "react";
    
    export default class index extends Component {
      render() {
        console.log("About组件收到的props是", this.props);
        return <div>About</div>;
      }
    }
    
  2. App.jsx中的about是路由组件

    import React, { Component } from "react";
    import { Link, BrowserRouter, Route } from "react-router-dom";
    import Home from "./pages/Home"; // Home是路由组件
    import About from "./pages/About"; // About是路由组件
    
    <BrowserRouter>
                <div className="col-xs-2 col-xs-offset-2">
                  <div className="list-group">
                    {/* React中靠路由链接实现切换组件 */}
                    <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 path="/about" component={About}></Route>
                      <Route 
    
    path="/home" component={Home}></Route>
                    </div>
                  </div>
                </div>
              </BrowserRouter>
    

image-20221118090749535

4-2-4-2 区别
  1. 写法不同:

    • 一般组件:<Demo/>
    • 路由组件:<Route path="/demo" componet = {Demo}>
  2. 存放位置不同:

    • 一般组件:components
    • 路由组件:pages
  3. 接收到的props不同:

    • 一般组件:写组件标签时传递了什么,就能收到什么
    • 路由组件:接收到三个固定的属性
    history:
        go: ƒ go(n)
        goBack: ƒ goBack()
        goForward: ƒ goForward()
        push: f  push(path, state)
        replace: f replace(path, state)
    location:
        pathname: "/about"
        search: ""
        state: undefined
    match:
        params: {}
        path: "/about"
        url: "/about"
    

4-2-5 NavLink的使用

  1. <NavLink
                     activeClassName="active"
                     className="list-group-item"
                     to="/about"
                   >
                     About
                   </NavLink>
                   <NavLink
                     activeClassName="active"
                     className="list-group-item"
                     to="/home"
                   >
    
  2. 封装NavLink组件

    • NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
    • 标签体内容是一个特殊的标签属性
    • 通过this.props.children可以获取标签体内容
  3. 封装的NavLink组件

    • MyNavLink组件:

      import React, { Component } from "react";
      import { NavLink } from "react-router-dom";
      
      export default class MyNavLink extends Component {
        render() {
          console.log(this.props);
          // const { to, title, a, b } = this.props;
          return (
            <div>
              <NavLink
                activeClassName="active"
                className="list-group-item"
                {...this.props}
              >
                {/* {this.props.children} */}
              </NavLink>
            </div>
          );
        }
      }
      
      
    • App.jsx

      import React, { Component } from "react";
      import { BrowserRouter, Route } from "react-router-dom";
      import Home from "./pages/Home"; // Home是路由组件
      import About from "./pages/About"; // About是路由组件
      import Header from "./components/Header"; // Header是一般组件
      import MyNavLink from "./components/MyNavLink/index";
      
         <div className="list-group">
                      {/* React中靠路由链接实现切换组件 */}
                      <MyNavLink to="/home" title="Home" a="jj" b="hh">
                        Home
                      </MyNavLink>
                      <MyNavLink to="/about">About</MyNavLink>
                      <MyNavLink to="/about" children="about">
                        About
                      </MyNavLink>
                    </div>
      

4-2-6 Switch的使用

    • 通常情况下,path和component是一一对应的关系
    • Switch可以提高路由匹配效率(单一匹配)
  1. import { BrowserRouter, Route, Switch } from "react-router-dom";
    
    <Sw  itch>
                        {/* 注册路由 */}
                        <Route path="/about" component={About}></Route>
                        <Route path="/home" component={Home}></Route>
                        <Route path="/home" component={Test}></Route>
                      </Switch>
    

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

  1. public/index.html 中 引入样式时不写 ./ ,写/

  2. public/index.html 中引入样式不屑 ./ ,写%PUBLIC_URL%(常用)

  3. 使用HashRouter

  4. public文件夹相当于localhost的根路径

    • http://localhost:3000/css/bootstrap.css
      http://localhost:3000/ttt/css/bootstrap.css
      

4-2-8 路由的模糊匹配与严格匹配

  1. Linke的to必须包含 路由组件的path

    <Link to="/home/a/b"></Link>
    <Route path="/home" component={home}>  
    /* 模糊匹配 */
    
    • 【输入的路径】必须包含【匹配的路径】,且顺序要一致
  2. 严格匹配

    <Route exact={true} path="/home" component={home}> 
    
    • 严格匹配不要随便开启

4-2-9 Redirect的使用

  1. React 6.0:
    • <Route path="*" element={<Navigate to="/about" />} />
  2. <Redirect to="/home">
    • 一般写在所有路由的最下方,当所有路由都无法匹配时候,跳转到Redirect指定的路由
  3. 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

4-3 嵌套路由

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

4-3-1 向路由组件传递参数数据

4-3-1-1 向路由组件传递params参数
  1. params参数:

    • 路由链接(携带参数) : <Link to="/demo/test/tome/18">详情</Link>

    • 注册路由(生命接收) :

      <Route path="demo/test/:name/:age" component={Test}></Route>

    • 接收参数:

      const {id,title} = this.props.match.params

  2. Message向Detail组件传递数据

    • Message

      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>
              <div>
                <div className="row">
                  <div>
                    <ul>
                      {messageArr.map((msgObj) => {
                        return (
                          <li key={msgObj.id}>
                            {/* 向路由组件传递params参数 */}
                            <Link
                              to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}
                            >
                              {msgObj.title}
                            </Link
                          </li>
                        );
                      })}
                    </ul>
                    <hr />
                    {/* 声明接收params参数 */}
                    <Route
                      path="/home/message/detail/:id/:title"
                      component={Detail}
                    ></Route>
                  </div>
                </div>
              </div>
            </div>
          );
        }
      }
      
      
    • Detail

      import React, { Component } from "react";
      import qs from "query-string";
      
      let obj = { name: "tom", age: 18 }; // key=value & key=value
      console.log(qs.stringify(obj));
      
      // let str = "carName=奔驰&price=199";
      
      const DetailData = [
        { id: "01", content: "你好,中国" },
        { id: "02", content: "你好,aaa" },
        { id: "03", content: "你好,abbb" },
      ];
      export default class Detail extends Component {
        render() {
          console.log(this.props);
      
          const { id, title } = this.props.match.params;   // 接收params参数
      
          const findResult = DetailData.find((detailObj) => {
            return detailObj.id === id;
          });
          return (
            <div>
              <ul>
                <li>ID: {id}</li>
                <li>Title: {title}</li>
                <li>CONTENT: {findResult.content}</li>
              </ul>
            </div>
          );
        }
      }
      
      
4-3-1-3 向路由组件传递search参数
    • 路由链接(携带参数):<Link to='/demo/test?name=tome&age=18'>详情</Link>

    • 注册路由(无需声明,正常注册即可):<Route path="/demo/test" componnet={Test}>

    • 接收参数:this.props.location.search

      image-20221126094937770

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

      image-20221126095236399

    • Message

      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>
              <div>
                <div className="row">
           
                    <div>
                    <ul>
                      {messageArr.map((msgObj) => {
                        return (
                          <li key={msgObj.id}>
                            {/* 向路由组件传递search参数 */}
                            <Link
                              to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}
                            >
                              {msgObj.title}
                            </Link>
                            &nbsp;&nbsp;
                          </li>
                        );
                      })}
                    </ul>
                    <hr />
                    {/* 生命接受search参数 */}
                    <Route path="/home/message/detail" component={Detail}></Route>
                  </div>
                </div>
              </div>
            </div>
          );
        }
      }
      
      
    • Detail

      import React, { Component } from "react";
      import qs from "querystring";
      
      let obj = { name: "tom", age: 18 }; // key=value & key=value
      console.log(qs.stringify(obj));
      
      const DetailData = [
        { id: "01", content: "你好,中国" },
        { id: "02", content: "你好,aaa" },
        { id: "03", content: "你好,abbb" },
      ];
      export default class Detail extends Component {
        render() {
          console.log(this.props);
          // 接收search参数
          const { search } = this.props.location;
          const { id, title } = qs.parse(search.slice(1));
      
          const findResult = DetailData.find((detailObj) => {
            return detailObj.id === id;
          });
          return (
            <div>
               <ul>
                <li>ID: {id}</li>
                <li>Title: {title}</li>
                <li>CONTENT: {findResult.content}</li>
              </ul>
            </div>
          );
        }
      }
      
4-3-1-4 向路由组件传递state参数
  1. 路由链接: <Link to={{path:'/demo/test?name=tome&age=18'}}>详情</Link>

  2. 注册路由(无需声明,正常注册即可):

    <Route path="/demo/test" componnet={Test}>

  3. 接收参数:this.props.location.state

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

4-3-2 多种路由跳转方式

4-3-2-1
  1. push和replace

    <Link replace to='/home'/>

    • 登录成功之后,不准用户返回登陆界面

4-4 其他

4-4-1 push与replace

  1. <Link replace={true} to={{path:'/demo/test?name+tome&age=18'}}>详情</Link>

4-4-2 编程式路由导航

不用Link,也不用NavLink

一、 携带params参数

  1. 编写代码,事件触发之后执行,自动跳转到Detail组件,且为replace跳转

    this.props.history.replace(`/home/message/detail/${id}/${title}`)
    
  2. this.props.history.push(`/home/message/detail/${id}/${title}`)
    

二、 携带search参数

this.props.hostory.replace(`/home/message/detail?id=${id}&title=${title}`)

三、 state参数

this.props.history.replace(`/home/message/detail`)

四、

  1. replaceShow = (id,title) => { 
     // 编写代码,replace跳转至 Detail(携带params参数)
      this.props.history.replace(`/home/message/detail/${id}/${title}`)
      // replace跳转+携带search参数
      this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
      // replace跳转+携带state参数
      this.props.history.replace(`/home/message/detail`, {id,title})
    }
    
    
    
      <button onClick={ () => this.replaceShow(msgObj.id,msgObj.title) }>replace查看</button>
    

4-4-3 withRouter的使用

    • withRouter可以加工一般组件,让一般组件具备路由组件所特有的api
    • withRouter的返回值是一个新组件
    • goback()
    • go()
    • goforward()
    • push
    • replace
  1. import {withRouter} from 'react-router-dom'
    
    back = () => {
        this.props.history.goBack()
    }
    
    <button onCLick={this.back}>回退</button>
    

4-4-4 BrowserRouter与HashRouter

  1. 底层原理不一样:
    • BrowserRouter使用的是H5的history API,不兼容IE9及以下版本
    • HshRouter使用的是URL的哈希值
  2. URL表现形式不一样
    • BrowserRouter的路径中没有#
  3. 刷新后对路由state参数的影响
    • BrowserRouter没有任何影响,因为state保存在history对象中
    • HashRouter刷新后会导致路由state参数的丢失
  4. HashRouter可以用于解决一些路径错误相关的问题

4-5 ReactRouter6教程

4-5-1 概述

  1. React Router以三个不同的包发布到npm上,分别为:
    • react-router: 路由的核心库,提供了:组件、钩子
    • react-touter-dom: 包含react-router所有内容,并添加一些专门用于DOM的组件
      • <BrowserRouter>
    • react-router-native:
      • 包含react-router所有内容,并添加一些专门用于ReactNative的API,<NativeRouter>
  2. 与React Router5.x版本比:
    • 内置组件的变化:移除<Switch>,新增<Routes>
    • 语法的变化 : <component={About}>变为element={<About>}
    • 新增多个hook:usePrams/useNavigate/useMatch

Component


4-5-1-1 <Routes/><Route/>
  1. <Routes/><Route/>

    • <Route caseSensitive>属性用于指定: 匹配时是否区分大小写
    • <Route>也可以嵌套使用,且可配合useRoutes()配置“路由表”,但需要通过<Outlet>组件来渲染子路由
  2. 例子:

       <div className="row">
                <div className="col-xs-2 col-xs-offset-2">
                  <div className="list-group">
                    {/* React中靠路由链接实现切换组件 */}
                 
                    <NavLink className="list-group-item" to="/about">About</NavLink>
                    <NavLink className="list-group-item" to="/home">Home</NavLink>
                  </div>
                </div>
                <div className="col-xs-6">
                  <div className="panel">
                    <div className="panel-body">
                      <Routes>
                        {/* 注册路由 */}
                        <Route path="/about" element={<About/>}/>
                        <Route path="/home" element={<Home />} />
                        {/* <Route path="/home" element={<Demo/>}/> */}
                        <Route path="/" element={<Navigate to="/about"/>} />
                        {/* <Redirect to="/home"></Redirect> */}
                      </Routes>
                    </div>
                  </div>
                </div>
            </div>
    
4-5-1-2 <NavLink>
  1. <Link>组件类似,可以实现导航的“高亮”效果

  2. // NavLink默认类名是active,指定自定义的class
    <NavLink to="login" className={({ isActive }) => {
        console.log('home',isActive)
        return isActive ? 'base one' : 'base'
        }>login</NavLink>
    
    // 默认情况下,home的子组件匹配成功,Home的导航也会高亮
    当NavLink上添加了end属性后,若Home的子组件匹配成功,则Home的导航没有高亮效果
    <NavLink to="home" end>Home</NavLink>
    
4-5-1-3 <Navigate>
  1. 只要<Navigate>组件被渲染,就会修改路径,切换视图

  2. replace属性用于控制跳转模式(push/replace)

  3. <Navgate to="/about" replace={true}>
    

4-5-2 Hooks

4-5-2-1 useRoutes路由表
  1. routes下的index.js

    import About from '../pages/About'
    import Home from '../pages/Home'
    import { Navigate } from 'react-router-dom'
    export default [
      {
        path: '/about',
        element: <About></About>
      },
      {
        path: '/home',
        element: <Home></Home>
      },
      {
        path: '/',
        element: <Navigate to="/about"/>
      }
    ]
    
  2. App组件

     const element = useRoutes([
        {
          path: '/about',
          element: <About></About>
        },
        {
          path: '/home',
          element: <Home></Home>
        },
        {
          path: '/',
          element: <Navigate to="/about"/>
        }
      ])
     
     <div className="panel-body">
                  {/* 注册路由 */}
                      {element}
      </div>
    
4-5-2-2 useNavigate()
  1. 作用:返回一个函数用来实现编程式导航

  2. navigate('/login',{
        replace: false,
        state: {a:1, b:2}
    })
    navigate(-1)
    
4-5-2-3 useParams()
  1. 返回当前匹配路由的params参数,match.params

  2. 
    
4-5-2-4 useSearchParams()
  1. 作用: 用于读取和修改当前位置的URL中的查询字符串
  2. 返回一个包含两个值的数组,内容:当前search参数、更新search中的函数
4-5-2-5 useLocation()
  1. 获取当前location信息,对标5.x中的路由组建的location属性

4-5-2 重定向

  1. <Route path="/" element={<Navigate to="/about"/>} />
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值