UmiJS学习
UmiJS4学习笔记
起步
官网学习:https://umijs.org/
开发环境
Umi.js 需要使用 Node.js来进行开发,因此请先确保电脑已经安装了 Node.js 且版本在 14 以上。
安装pnpm:npm install pnpm -g
创建项目
Umi 官方提供了一个脚手架 ,可以轻松快速创建一个项目:
pnpm dlx create-umi@latest
创建时会进行三个选择:
Pick Umi App Template ?> Simple App // 普通项目> Ant Design Pro // 使用了umi max> Vue Simple App // vue项目
Pick Npm Client ?> npm> cnpm> tnpm> yarn> pnpm (推荐)
Pick Npm Registry ?> npm> taobao (推荐)
选择完成 -> 等待项目创建。
路由
配置路由
在config/config.ts或者umirc.ts中通过routes进行配置:
export default {routes: [{ path: '/', component: 'index' }, { path: '/user', component: 'user' },],
}
path
只支持两种占位符
:id 的形式
*通配符,只能出现路由字符串的最后。
component
用于匹配成功后渲染的 React 组件路径。如果是相对路径,会从 src/pages 开始找起。
如果指向 src 目录的文件,可以用 @,也可以用 ../。比如 component: '@/layouts/basic',或者 component: '../layouts/basic',推荐用前者。
routes
export default { routes: [ { path: '/login', component: 'login' }, { path: '/', component: '@/layouts/index', routes: [ // 子路由 { path: '/list', component: 'list' }, { path: '/admin', component: 'admin' }, ], }, ], }
通过**<Outlet/ >**进行子路由渲染
rediret
export default { routes: [ { path: '/', redirect: '/list' }, // 访问 / 会跳转到 /list,并由 src/pages/list 文件进行渲染。 { path: '/list', component: 'list' }, ], }
wrappers
export default { routes: [ { path: '/user', component: 'user', wrappers: [ '@/wrappers/auth', ], }, { path: '/login', component: 'login' }, ] }
然后在 src/wrappers/auth 中,
import { Navigate, Outlet } from 'umi' export default (props) => { const { isLogin } = useAuth(); if (isLogin) { return <Outlet />; } else{ return <Navigate to="/login" />; } }
title
配置路由的标题。
加载组件
在项目 src 目录下创建 loading.tsx 或者 loading.jsx 或者 loading.js 文件,默认导出的组件会在组件加载的时候渲染。
const Loading:React.FC = () => { return( <div> <h1>正在加载中。。。</h1> </div> ) } export default Loading;
可以将开发者模式的网络切换为3G慢速查看效果
路由传参
Umi4 使用 react-router@6 作为路由组件,路由参数的获取使其 hooks。(参考react-router@6)
数据加载
在路由文件中,除了默认导出的页面组件外,再导出一个 clientLoader 函数,并且在该函数内完成路由数据加载的逻辑。
// pages/.../some_page.tsx import { useClientLoaderData } from 'umi'; export default function SomePage() { const data = useClientLoaderData(); return <div>{data}</div>; } export async function clientLoader() { const data = await fetch('/api/data'); return data; }
如上代码,在 clientLoader 函数返回的数据,可以在组件内调用 useClientLoaderData 获取。
Mock
Umi 约定 /mock 目录下的所有文件为 Mock 文件
Mock 文件默认导出一个对象,而对象的每个 Key 对应了一个 Mock 接口,值则是这个接口所对应的返回数据
export default { // 返回值可以是数组形式 'GET /api/users': [ { id: 1, name: 'foo' }, { id: 2, name: 'bar' } ], // 返回值也可以是对象形式 'GET /api/users/1': { id: 1, name: 'foo' }, }
自定义函数
export default { 'POST /api/users/create': (req, res) => { // 添加跨域请求头 res.setHeader('Access-Control-Allow-Origin', '*'); res.end('ok'); } }
关于 req 和 res 的 API 可参考 Express@4 官方文档 来进一步了解。
关闭 Mock
Umi 默认开启 Mock 功能,如果不需要的话可以从配置文件关闭:
// .umirc.ts export default { mock: false, };
引入 Mock.js
生成随机的模拟数据
import mockjs from 'mockjs'; export default { // 使用 mockjs 等三方库 'GET /api/tags': mockjs.mock({ 'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }], }), };
代理
只需在配置文件中加上以下代码:
proxy: { '/api': { 'target': 'http://jsonplaceholder.typicode.com/',proxy: { '/api': { 'target': 'http://jsonplaceholder.typicode.com/', 'changeOrigin': true, 'pathRewrite': { '^/api' : '' }, }, },
将 /api 前缀的请求,代理到 http://jsonplaceholder.typicode.com/
将请求来源修改为目标url
替换请求地址中的 /api 为 ''
▲ proxy 暂时只能解开发时(dev)的跨域访问问题,生产上的发生跨域问题的话,可以将类似的配置转移到 Nginx 容器上。
样式
CSS Modules
在 js 文件中引入样式时,如果赋予他一个变量名,就可以将样式以 CSS Module 的形式引入。
import styles from './index.css'; export default function () { return <div className={styles.title}> Hello World </div>; }
微生成器
使用
下面的命令会列出目前所有可用的生成器,可以通过交互式方式来选择你使用的功能,都有详细的提示。
$ umi generate # 或者 $ umi g
你也可以通过 umi g <generatorName> 的形式来使用对应的生成器。
生成器列表
参考官方文档:https://umijs.org/docs/guides/generator
数据流
model
这里以一个计数器为例
创建model
// src/models/counter.ts import { useState } from "react" export default () => { const [num, setNum] = useState(0); const increment = (num: number) => { setNum(num + 1); } const decrement = (num: number) => { setNum(num - 1); } return { num, increment, decrement } }
使用model
const Children01: React.FC = () => { const { num, increment, decrement } = useModel('counter'); return ( <h1>计数器model</h1> <h2>这是结果:{num}</h2> <button onClick={() => { increment(num) }}>+1</button> <button onClick={() => { decrement(num) }}>-1</button> <hr /> ) }
这就是一个 Model。插件所做的工作就是将其中的状态或数据变成了全局数据,不同的组件在使用该 Model 时,拿到的是同一份状态或数据。
性能优化
useModel() 方法可以接受可选的第二个参数,当组件只需要使用 Model 中的部分参数,而对其它参数的变化不感兴趣时,可以传入一个函数进行过滤。
const { add, minus } = useModel('counterModel', (model) => ({ add: model.increment, minus: model.decrement, }));
全局初始状态
全局初始状态在整个 Umi 项目的最开始创建。
编写 src/app.ts 的导出方法 getInitialState(),其返回值将成为全局初始状态。
// src/app.ts import { fetchInitialData } from '@/services/initial'; export async function getInitialState() { const initialData = await fetchInitialData(); return initialData; }
现在,各种插件和您定义的组件都可以通过 useModel('@@initialState') 直接获取到这份全局的初始状态
import { useModel } from 'umi'; export default () => { const { initialState, loading, error, refresh, setInitialState } = useModel('@@initialState'); return <>{initialState}</>; };
请求
request
request 接收的 options除了透传 axios 的所有 config 之外,
我们还额外添加了几个属性 skipErrorHandler,getResponse,requestInterceptors 和 responseInterceptors 。
request('/api/user', { params: { name : 1 }, timeout: 2000, // other axios options skipErrorHandler: true, getResponse: false, requestInterceptors: [], responseInterceptors: [], }
useRequest
插件内置了 @ahooksjs/useRequest ,你可以在组件内通过该 Hook 简单便捷的消费数据。
import { useRequest } from 'umi'; export default () => { const { data, error, loading } = useRequest(() => { return services.getUserList('/api/test'); }); if (loading) { return <div>loading...</div>; } if (error) { return <div>{error.message}</div>; } return <div>{data.name}</div>; };
request配置
在 src/app.ts 中你可以通过配置 request 项,来为你的项目进行统一的个性化的请求设定。
import type { RequestConfig } from 'umi'; export const request: RequestConfig = { timeout: 1000, // other axios options you want errorConfig: { errorHandler(){ }, errorThrower(){ } }, requestInterceptors: [], responseInterceptors: [] };
在这里配置的规则将应用于所有的 request 和 useRequest 方法。
errorConfig
接收你后端返回的数据并且需要抛出一个你自己设定的 error, 你可以在这里根据后端的数据进行一定的处理。
request 会 catch errorThrower 抛出的错误,并且执行你的 errorHandler 方法,
该方法接收两个参数,第一个参数是 catch 到的 error,第二个参数则是 request 的 opts。
requestInterceptors
为 request 方法添加请求阶段的拦截器。
传入一个数组,每个元素都是一个拦截器。
const request: RequestConfig = { requestInterceptors: [ // 直接写一个 function,作为拦截器 (url, options) => { // do something return { url, options } }, // 一个二元组,第一个元素是 request 拦截器,第二个元素是错误处理 [(url, options) => {return { url, options }}, (error) => {return Promise.reject(error)}], // 数组,省略错误处理 [(url, options) => {return { url, options }}] ] }
responseInterceptors
为 request 方法添加响应阶段的拦截器。
传入一个数组,每个元素都是一个拦截器。
const request: RequestConfig = { responseInterceptors: [ // 直接写一个 function,作为拦截器 (response) => { // 不再需要异步处理读取返回体内容,可直接在data中读出,部分字段可在 config 中找到 const { data = {} as any, config } = response; // do something return response }, // 一个二元组,第一个元素是 request 拦截器,第二个元素是错误处理 [(response) => {return response}, (error) => {return Promise.reject(error)}], // 数组,省略错误处理 [(response) => {return response}] ] }
dva
配置dva
首先你需要在umirc.ts里配置 dva: {} 打开 Umi 内置的 dva 插件。
添加model
model 的写法参考如下示例:
export default { state: { user: { name: 'zhangsan' }, }, effects: { *setName({ payload }: any, { call, put }: any) { console.log('异步访问') yield put({ type: 'update', payload: payload }) } }, reducers: { update(state: any, action: any) { return { ...state, ...action.payload } }, test(state: any) { console.log('test'); return state; }, }, }
connect
把组件和 model connect 在一起,并在组件中 dispatch 事件
const Children03 = (props: any) => { return ( <div> <h1>获取state</h1> <h2>{props.user.user.name}</h2> <button onClick={() => { props.dispatch({ type: 'user/update', payload: { user: { name: 'lisi' } } }) }}>修改name·同步</button><br /><br /> <button onClick={() => { props.dispatch({ type: 'user/setName', payload: { user: { name: 'wangwu' } } }) }}>修改name·异步</button> <hr /> </div> ) } export default connect(({ user }: any) => ({ user, }))(Children03);
文档
model
namespace # model 的命名空间,唯一标识一个 model,如果与文件名相同可以省略不写
state # model 中的数据
effects # 异步 action,用来发送异步请求
reducers # 同步 action,用来修改 state
connect
connect 的是用来将 model 和组件关联在一起的,它会将相关数据和 dispatch 添加到组件的 props 中。
dispatch
在使用 connect 将组件和 model 关联在一起的同时框架也会添加一个 this.props.dispatch 的方法,通过该方法你可以触发一个 action 到 model 中。
Reducer
reducer 是一个函数,用来处理修改数据的逻辑(同步,不能请求后端)。接受 state 和 action,返回老的或新的 state 。即:(state, action) => state。
Effects
put 用于触发 action 。
yield put({ type: 'todos/add', payload: 'Learn Dva' });
call 用于调用异步逻辑,支持 promise 。
const result = yield call(fetch, '/todos');
select 用于从 state 里获取数据。
const todos = yield select(state => state.todos);
loading 框架会默认添加一个命名空间为 loading 的 model,该 model 包含 effects 异步加载 loading 的相关信息,它的 state 格式如下:
{ global: Boolean, // 是否真正有异步请求发送中 models: { [modelnamespace]: Boolean, // 具体每个 model 的加载情况 }, effects: { [modelnamespace/effectname]: Boolean, // 具体每个 effect 的加载情况 }, }
相关文章:
UmiJS学习
UmiJS4学习笔记起步官网学习:https://umijs.org/开发环境Umi.js 需要使用 Node.js来进行开发,因此请先确保电脑已经安装了 Node.js 且版本在 14 以上。安装pnpm:npm install pnpm -g创建项目Umi 官方提供了一个脚手架 ,可以轻松快…...
Leetcode:322. 零钱兑换(C++)
目录 问题描述: 实现代码与解析: 动态规划(完全背包): 原理思路: 问题描述: 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金…...

C经典小游戏之扫雷
编译环境:VS022 目录 1.算法思路 2.代码模块 2.1 game.h 2.2 game.cpp 2.3 test.cpp 3.重点分析 4.金句省身 1.算法思路 主要采用二维数组进行实现,设置两个二维数组,一个打印结果,即为游戏界面显示的效果,一个用…...

第十节 使用设备树插件实现RGB 灯驱动
Linux4.4 以后引入了动态设备树(Dynamic DeviceTree),我们这里翻译为“设备树插件”。设备树插件可以理解为主设备树的“补丁”它动态的加载到系统中,并被内核识别。例如我们要在系统中增加RGB 驱动,那么我们可以针对R…...
【LeetCode】公交路线 [H](宽度优先遍历)
815. 公交路线 - 力扣(LeetCode) 一、题目 给你一个数组 routes ,表示一系列公交线路,其中每个 routes[i] 表示一条公交线路,第 i 辆公交车将会在上面循环行驶。 例如,路线 routes[0] [1, 5, 7] 表示第 …...

报表生成器 FastReport .Net 用户指南 2023(十):Band的属性
FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案,使用FastReport .NET可以创建独立于应用程序的.NET报表,同时FastReport .Net支持中文、英语等14种语言,可以让你的产品保证真正的国际性。 FastReport.NET官方版…...

DAMA数据管理知识体系指南之文档和内容管理
第10章 文档和内容管理 10.1 简介 文档和内容管理是对存储在关系数据库以外的信息的采集、存储、访问以及使用的控制活动。文档和内容管理的侧重点在完整性和访问控制上。因此,它与关系数据库的数据操作管理大致相同。由于多数非结构化数据与存储在结构化文件中的…...
C++入门:数据结构
C/C 数组允许定义可存储相同类型数据项的变量,但是结构是 C 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性&#x…...

C语言实现烟花表白,内含源码!!
虽然现在看烟花有一定难度,但代码式烟花可以随时随地看! 烟花的代码很多,实际上是可以用 Python、HTML5 等语言写烟花,但今天主要想和大家分享用C语言写的烟花代码,非常细致和实用。 同学们一定要亲自敲一遍…...

虚拟机安装CentOS 7(带界面)
目录 一、虚拟机安装CentOS 7(带界面) 1、打开下好的VMware,点击创建虚拟机 2、下一步 3、点击下一步 4、选择Linux,ContOS7,点击下一步 5、修改虚拟机名称和路径 6、下一步 7、点击自定义硬件 8、设置虚拟机大…...

Java测试——selenium具体操作
selenium的前置准备工作可以参考我之前的博客:Java测试——selenium的安装与使用教程 这篇博客讲解一下selenium的常见操作 先创建driver ChromeDriver driver new ChromeDriver();输入网址 driver.get("https://www.baidu.com");常见操作 查找元素…...

电子器件系列32:逻辑与门芯片74LS11
一、编码规则 先看看这个代码的意思:74LS11 74是一个系列(74 表示为工作温度范围,74: 0 ~ 70度。) ls的意思就是工艺类型(Bipolar(双极)工艺) 11是代码 什么是74系列逻辑芯片? - 知乎 什么是…...

LeetCode-101. 对称二叉树
目录题目分析递归法题目来源 101. 对称二叉树 题目分析 首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点! 对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一…...
使用intlinprog求解指派问题MATLAB代码分享
% 输入指派矩阵C [3 8 2 10 3;8 7 2 9 7;6 4 2 7 5;8 4 2 3 5;9 10 6 9 10];f C(:); %生成一个列向量,作为目标函数系数,matlab默认以列排序[m,n] size(C);Aeq zeros(2*n,n*n); %2*n个等式约束,n*n个变量for i 1:n %这里先生成的是后5个…...

Spark On YARN时指定Python版本
坑很多,直接上兼容性最佳的命令,将python包上传到hdfs或者file:/home/xx/(此处无多余的/) # client 模式 $SPARK_HOME/spark-submit \ --master yarn \ --deploy-mode client \ --num-executors 2 \ --conf "spark.yarn.dist.archives<Python包…...
[数据库]库的增删改查
●🧑个人主页:你帅你先说. ●📃欢迎点赞👍关注💡收藏💖 ●📖既选择了远方,便只顾风雨兼程。 ●🤟欢迎大家有问题随时私信我! ●🧐版权:本文由[你帅…...

Wine零知识学习1 —— 介绍
一、什么是Wine Wine是“Wine Is Not an Emulator” 的首字母缩写,是一个能够在多种POSIX-compliant操作系统(诸如Linux、macOS及BSD等)上运行 Windows 应用的兼容层。Wine不像虚拟机或者模拟器那样模仿内部的Windows逻辑,而是將…...

设计模式--建造者模式 builder
设计模式--建造者模式 builder)建造者模式简介建造者模式--小例子(电脑购买)1.产品类2.抽象构建者3.实体构建类4.指导者类5.客户端测试类小结建造者模式简介 建造者模式有四个角色,概念划分如下: Product : 产品类&a…...

终于周末啦,继续来总结一下Python的一些知识点啦
目录 Python概念梳理 常见概念梳理 Python经典判断题 判断题 选择题 Python概念梳理 常见概念梳理 Python中,不仅仅变量的值是可以变化的,类型也是可以随时变化的 1、Python的变量必须初始化否则提示 is not defined 2、if、while中定义的变量在…...

CUDA By Example(八)——流
文章目录页锁定主机内存可分页内存函数页锁定内存函数CUDA流使用单个CUDA流使用多个CUDA流GPU的工作调度机制高效地使用多个CUDA流遇到的问题(未解决)页锁定主机内存 在之前的各个示例中,都是通过 cudaMalloc() 在GPU上分配内存,以及通过标准的C库函数 …...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...