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

一.高阶组件装饰器

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

作用:使用装饰器可以大大简化代码,让高阶组件代码更优雅, 同时也解决了多层嵌套的问题(使
      用了装饰器语法后, 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"),  
        }) 
    );
javascript 复制代码
3. 配置babel:(装饰器是 ES7 的新语法,浏览器,nodejs 不一定支持,需要 babel 转译)
在项目根目录下创建 .babelrc 并写入以下内容:
{  
    "presets": [  "@babel/preset-env"  ],  
    "plugins": [  
        [  
            "@babel/plugin-proposal-decorators",  
            {  
                "legacy": true  
            }  
        ]  
    ] 
}
javascript 复制代码
4. 修改`package.json`中的脚本命令为:(全部修改完成后重启项目)
"scripts": {  
    "start": "react-app-rewired start",  
    "build": "react-app-rewired build",  
    "test": "react-app-rewired test",  
    "eject": "react-app-rewired eject" 
} 

二.路由

javascript 复制代码
实现路由功能可使用的包有两个: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的语句,也就是说他必须写在组件的最顶层
javascript 复制代码
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三个路由对象,从而实现可以使用编程式导航的路由跳转
            );
        }
    }
}
相关推荐
Hello-Mr.Wang13 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘40 分钟前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
编程零零七4 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
(⊙o⊙)~哦6 小时前
JavaScript substring() 方法
前端
无心使然云中漫步6 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者6 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_7 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋8 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120538 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢8 小时前
【Vue】VueRouter路由
前端·javascript·vue.js