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库函数 …...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
