day57(reactJS)续上篇的高阶组件装饰器以及路由

news/2024/7/15 18:03:50 标签: react.js, 前端, 前端框架, webpack

一.高阶组件装饰器

来由:当有多种组件逻辑需要重用的时候,会需要创建多个高阶组件,此时如果使用层层嵌套方式来
      增强组件逻辑,会使代码变得抽象,难以理解,这种情况下需要使用到装饰器语法

作用:使用装饰器可以大大简化代码,让高阶组件代码更优雅, 同时也解决了多层嵌套的问题(使
      用了装饰器语法后, Hoc高阶组件在编译阶段就会执行, 并且可以自动将@下方的 组件作为参
      数传入高阶组件, 这使得代码书写更加优雅)
      
注意事项::::
1. 装饰器对类的行为的改变是在代码编译时发生的,而不是在运行时,这意味着,装 饰器能在编译阶段运行代码,它本身就是编译时执行的函数
2. 装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升, 类是不会提 升的,所以就没有这方面的问题

使用步骤:
1. 运行指令下载插件:npm install react-app-rewired customize-cra (customize-cra 依赖于 react-app-rewired,两者需要一起安装)
2.webpack 进行配置:在当前项目根目录下面创建一个名称为config-overrides.js文件,文件中加入以下代码:
 const {  
        override,  
        addDecoratorsLegacy,  
        disableEsLint,  
        addBundleVisualizer,  
        addWebpackAlias,  
        adjustWorkbox 
        } = require("customize-cra"); 
const path = require("path"); 
module.exports = override(  
        disableEsLint(), ----------------webpack 中禁用 eslint
        addDecoratorsLegacy(),---------------添加装饰器语法
        addWebpackAlias({-----------添加 webpack 别名  
        ["@"]: path.resolve("./src"),  
        }) 
    );
3. 配置babel:(装饰器是 ES7 的新语法,浏览器,nodejs 不一定支持,需要 babel 转译)
在项目根目录下创建 .babelrc 并写入以下内容:
{  
    "presets": [  "@babel/preset-env"  ],  
    "plugins": [  
        [  
            "@babel/plugin-proposal-decorators",  
            {  
                "legacy": true  
            }  
        ]  
    ] 
}
4. 修改`package.json`中的脚本命令为:(全部修改完成后重启项目)
"scripts": {  
    "start": "react-app-rewired start",  
    "build": "react-app-rewired build",  
    "test": "react-app-rewired test",  
    "eject": "react-app-rewired eject" 
} 

二.路由

实现路由功能可使用的包有两个:react-router和react-router-dom,主要使用react-router-dom

使用步骤:(一级路由)
1. 运行指令安装插件:npm i react-router-dom@5(类组件适用5版本的包,函数组件适用于6版
   本的包)
   
2. 定义路由规则:在根组件App.jsx中,从react-router-dom路由库中导入Route组件,使用该组
   件作为标签定义路由规则(该组是路由组件,作用是充当组件渲染出口以及定义路由规则)
   
  语法:
  import { Route } from 'react-router-dom';
  <Route path='路由地址' component={导入的组件名称}/>(在这里绑定的组件都需要导入)
  注意:Route组件需要被包裹在Router路由管理组件中
  
3. 使用Router路由管理组件包裹根组件:在index.js入口文件中,从react-router-dom路由库中导入Router(HashRouter或者BrowserRouter)组件,并用该组件双标签包裹根组件(注意:整个项目只能有一个Router组件,所以在用来包裹在根组件外面,可以保证包裹该项目所有的Route组件)
  语法:
  import { BrowserRouter,HashRouter} from 'react-router-dom';
  <BrowserRouter><App /></BrowserRouter>;
  
4. 设置路由重定向的路由规则:从react-router-dom路由库中导入Redirect组件用于路由重定向,
    该组件的标签可以带两个属性:from(初始路由路径),to(重定向后的路由路径)
  语法:(注意重定向路由规则的标签要带exact精确匹配,防止错误路由因为都以“/”开头而成功匹配重定向路由路径)
  import { Redirect} from 'react-router-dom';
  <Redirect exact from='初始路由路径' to='重定向后的路由路径'></Redirect>
  
5. 设置404路由规则:404路由的路由规则使用Route组件定义
语法:(注意404路由规则的标签不带exact精确匹配)
<Route path='*' component={404组件}></Route>

6. 使用Switch组件:在每个定义了路由规则的组件中,从react-router-dom路由库中导入Switch
   组件,并将其包裹在该组件的路由规则语句外面(该组件的作用是使得url在第一次匹配成功之
   后放弃后续的匹配,主要解决错误url路由路径在成功匹配完重定向路由路径后又成功匹配最后
   的404路由路径,导致重定向对应的组件和404组件同时被渲染在页面的情况)
语法:
import { Switch }  from 'react-router-dom';
<Switch >
  <Route1 />;
  <Route2 />;
  ....
</Switch >


要点::::
1. exact:Route组件的属性,作用是精确匹配,
  1. 注意:
    1. 404路由规则不能添加该属性;
    2. 当一条路由规则下包含嵌套路由也不能添加该属性,否则会导致嵌套路由无法跳转;(精确匹配会导致url在一级路由那里就匹配失败,嵌套路由就没有机会匹配到)
    3. 
2. 路由跳转的执行过程:当我们在浏览器地址栏输入url或者通过跳转方法改变url后,会用该条路由与Route定义的所有路由规则进行自上而下,从一级路由到嵌套路由的匹配,如果匹配成功,就将对应路由规则绑定的组件渲染在路由规则定义的位置,匹配失败就继续下一条,直到匹配成功或者404路由(加上Switch组件之后,url会在匹配成功之后放弃后续匹配,否则会继续匹配,将所有匹配成功的路由规则对应的组件都渲染在其定义的位置。)
嵌套路由要点
定义:嵌套路由在需要的渲染位置定义路由规则,并且嵌套路由也需要设置重定向路由规则和404路由规则
两种导航方式

3. 标签式导航
Link与NavLink组件是用于跳转路由的组件,使用这两个组件实现路由跳转就属于标签式导航,使用时需要从react-router-dom路由库导入,这两个标签中都含有to属性,该属性的属性值就是跳转的路由路径
语法:(Link和NavLink组件的区别在于Link跳转路由时,对应的渲染a标签不能高亮,但NavLink在路由跳转时会给对应的渲染a标签添加class='active'属性,并移除其他未跳转的路由路径对应的渲染标签上的该属性,而这个属性就可以用来设置路由跳转时的标签高亮)
import { Link,NavLink } from 'react-router-dom';
<Link to='路由路径'></Link>
<NavLink to='路由路径'></NavLink>
4. 编程式导航
编程式导航需要通过路由管理对象来实现,而每个通过路由匹配渲染的组件的props中都会自动写入三个路由对象,其中就有包含路由跳转方法的对象history。
被写入的三个路由对象分别是:
history:该对象包含路由跳转的方法,该对象专门负责实现路由跳转(该对象中的go方法,参数为0时,代表刷新路由)
location:该对象保存和当前路由相关的信息,比如路由路径,路由参数等
match:该对象包含和当前路由相关的信息。
注意:只有经过路由匹配渲染的组件的props才会写入上述三个对象,才可以实现编程式导航,我们封装导入的子组件属于手动渲染,因此手动渲染的子组件的props是不会被写入上述三个对象,也就不能实现编程式导航。
			↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
想要让手动导入和渲染的子组件也能实现编程式导航的方法跳路由,可以通过高阶组件对该子组件进行逻辑增强的处理:需要在子组件编写的jsx文件内导入react-router-dom路由库提供的withRouter组件,在导出时使用该高阶组件将子组件进行处理(高阶组件也可以使用装饰器语法来使用)
语法:
import { withRouter } from  'react-router-dom';
export default withRouter(子组件)
路由懒加载(路由跳转对于初加载的优化写法)
路由懒加载一般使用react提供的suspense组件和lazy函数配合实现(用了懒加载就必须加上suspense,不然报错)
lazy:使用lazy函数处理的组件最终会单独打包到一个js文件中, 网页初次加载时只会加载需要的组件,其他组件等到访问对应的路由时才临时加载
suspense:在组件加载过程中首先渲染一个fallback组件,等到组件加载结束该fallback组件消失,正式的组件被渲染,该组件需要作为双标签嵌套在路由规则外面
语法:
import { lazy,suspense }  from 'react';
let 组件名 = lazy(()=>import('组件文件路径'));
<suspense fallback={<div>loading...</div>}>
<Route path='路由路径' component={组件名}></Route>;
......
</suspense>
小tips:import语句的上方不能出现非import的语句,也就是说他必须写在组件的最顶层
withRouter高阶组件的简单逻辑:

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

export function myWithRouter(Com){
    return class tool extends Component {
        render() {
            return (
                <Route component={Com} />----------使用导入的Route组件为目标子组件添加一个呗路由匹配和渲染的过程,使其props被写入history,location,match三个路由对象,从而实现可以使用编程式导航的路由跳转
            );
        }
    }
}

http://www.niftyadmin.cn/n/5414264.html

相关文章

spring中事务失效的场景有哪些?

异常捕获处理 在方法中已经将异常捕获处理掉并没有抛出。 事务只有捕捉到了抛出的异常才可以进行处理&#xff0c;如果有异常业务中直接捕获处理掉没有抛出&#xff0c;事务是无法感知到的。 解决&#xff1a;在catch块throw抛出异常。 抛出检查异常 spring默认只会回滚非检…

TypeScript新手指南:何时使用.ts,何时转向.tsx?

在TypeScript中&#xff0c;.ts和.tsx文件扩展名代表两种不同的文件类型&#xff1a; .ts&#xff1a;这是一个标准的TypeScript文件&#xff0c;它可以包含TypeScript代码&#xff0c;该代码最终会被编译成JavaScript。.ts文件通常不包含JSX代码&#xff0c;JSX是一种JavaScri…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Checkbox)

提供多选框组件&#xff0c;通常用于某选项的打开或关闭。 说明&#xff1a; API version 11开始&#xff0c;Checkbox默认样式由圆角方形变为圆形。 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口…

学习c语言:预处理详解(宏定义)

1.预定义符号 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //进⾏编译的源⽂件 __LINE__ //⽂件当前的⾏号 __DATE__ //⽂件被编译的⽇期 __TIME__ //⽂件被编译的时间 __STDC__ //如果编译器遵循ANSI C&…

JavaEE面试题

一、String面试题 1、String s1 "123"; 和 String s2 new String("123");的区别 在Java中&#xff0c;"String s1 "123";"和"String s2 new String("123");"这两行代码有一些重要的区别&#xff1a; "…

如何实现RabbitMQ、kafaka、rocketmq等消息队列的消息有序

文章目录 概述RabbitMQ消息有序kafka消息有序如何rocketmq的消息有序 概述 解决思路&#xff1a;将需要保证先后顺序的消息放到同一个队列&#xff0c;只用一个消费者去消费该队列。即保证入队有序&#xff0c;出队后的顺序交给消费者自己保证 大多数的项目是不需要保证 mq 消…

微信开发者工具 vim 键位绑定

问题&#xff1a;如标题 解决&#xff1a; 最上边点击设置&#xff0c;找到编辑器设置 点击更多编辑器设置&#xff0c;然后会弹出设置这个页面 搜索 vim &#xff0c;并点击 一直往下边滑动&#xff0c;找到 setting.json 然后加入这段代码&#xff1a; "vim.insertM…

Git误操作补救错失:恢复误删的本地分支、将某个提交从一个分支复制到另一个分支

一、恢复误删的本地分支 作为一枚强迫症&#xff0c;没用的分支总是喜欢及时删删删删掉删掉统统删掉&#xff0c;结果今天发现有些分支还是应该保留。 比如&#xff0c;①前段时间切了个分支用来专门做图表&#xff0c;但因为需求还没有最终确定&#xff0c;已经上线了测试服而…