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库函数 …...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
