最初只是使用react 进行开发项目,发现项目过大状态管理起来就相当困难,虽然有redux, mobx,但是使用起来还是相当繁琐,而目前umi有现成的轮子使用简单,当然愿意尝试了,趁现在假期有时间简单学习记录一下

一、安装umi

还是原来的套路,要使用先是安装一伙

$ npx @umijs/create-umi-app // if use npm

好了命令执行完成后目录是这样的

好接下来该开始着手开发了,但还有一件要注意的事情—

Umi官网目前已经是3.x版本了,注意这个版本与2.x有相当大差距,如:plugins 的配置

export default {
- plugins: [
- ['umi-plugin-react', {
- dva: {},
- antd: {},
- ...
- }]
- ],
+ dva: {},
+ antd: {},
+ ...
}

其他还有很多,如果刚从2.x升级3.x就要多留意了,否则会浪费不必要的时间,具体参照upgrade-to-umi-3

二、首页

使用antd layout 创建一个首页,这个demo比较简单,所有就直接官网照搬了,部分片段如下

import { Layout, Menu, Badge, Dropdown } from 'antd';
const { Header, Footer, Content } = Layout;
const logo = require('../../public/course/logo.jpeg'); export default function Page(props) {
return (
<Layout>
<Header className={styles.header}>
<img className={styles.logo} src={logo} alt="" />
<Menu
theme="dark"
mode="horizontal"
selectedKeys={selectedKeys}
style={{ lineHeight: '64px', float: 'left' }}
>
<Menu.Item key="/">
<Link to="/">商品</Link>
</Menu.Item>
<Menu.Item key="/users">
<Link to="/users">用户</Link>
</Menu.Item>
<Menu.Item key="/about">
<Link to="/about">关于</Link>
</Menu.Item>
</Menu>
</Header>
<Content className={styles.content}>
<div className={styles.box}>{props.children}</div>
</Content>
<Footer className={styles.footer}>learning</Footer>
</Layout>
);
}

三、路由配置

一个项目中路由应该是不可缺少的一部分,umi 3.x配置是直接在 .umirc.ts文件中

import { defineConfig } from 'umi';

export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
antd: {
compact: true,
},
dva: {
immer: true,
hmr: false,
},
routes: [
{
path: '/',
component: '@/layouts/index',
}
],
fastRefresh: {},
});

这里开启了antd 和dva 的插件使用,因为后期可能会使用到,好了这是可以yarn start 运行看看有一个简单的主页面了,但是点击一定会报错(路由没有配置完整)

四、鉴权

配置一个页面检测是否登录,当然首要任务是完善上面首页 中对应的菜单路由及页面创建了


创建目录和对应的文件,再完善路由

import { defineConfig } from 'umi';

export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
antd: {
compact: true,
},
dva: {
immer: true,
hmr: false,
},
routes: [
{ path: '/login', component: '@/pages/login' },
{
path: '/',
component: '@/layouts/index',
routes: [
{ path: '/', component: '@/pages/goods' },
{
path: '/about',
component: '@/pages/about'
},
{
path: '/users',
component: '@/pages/users/index',
routes: [
{
path: '/users/:oid/:id',
component: '@/pages/users/$oid/$id',
},
{ component: '@/pages/NotFound' },
],
},
{ component: '@/pages/NotFound' },
],
},
{ component: '@/pages/NotFound' },
],
fastRefresh: {},
});

好了路由大概是这个样子了,基本完成,

现在我们假如对about 页面做一个鉴权,其实也简单,创建一个wrappers目录,再在下面创建一个auth.tsx, 内容如:


import { Redirect } from 'umi' export default (props:any) => {
// 模拟鉴权
if (Math.random() > 0.5){
return <div>{ props.children }</div>;
} else {
return <Redirect to="/login" />;
}
}

再在about 路由增加wrappers, 修改如:

        {
path: '/about',
component: '@/pages/about',
wrappers: ['@/wrappers/auth'],
},

好了点击的时候就有50%机率到登录页面了

五、mock

目前是一个demo没有后台,所有使用mock模仿异步请求,在mock目录下创建一个login.js,简单的写一个login的接口

export default {
'post /api/login': (req, res) => {
const {
username,
password
} = req.body;
if (username == 'admin' && password == '123') {
var resObj = res.json({
code: 0,
data: {
token: 'admin123',
role: 'admin',
balance: 1000,
username: 'admin',
},
});
return resObj;
} if (username == 'dex' && password == '123') {
return res.json({
code: 0,
data: {
token: 'dex123',
role: 'user',
balance: 100,
username: 'dex',
},
});
}
return res.status(401).json({
code: -1,
msg: '密码错误',
});
},
};

六、models

目前还需要一个与mock接口进行交付的server,于是在models下创建一个user.js来管理用户登录相关的操作

import reqService from 'axios';
import { history } from 'umi'; const userinfo =
JSON.parse(localStorage.getItem('userinfo')) |
{
token: '',
role: '',
username: '',
blance: '',
};
// 登录请求
function loginReq(payload) {
return reqService.post('/api/login', payload).then((res) => {
return {
code: res.data.code,
userinfo: res.data.data,
};
});
} export default {
namespace: 'user',
state: userinfo,
effects: {
*login({ payload }, { call, put }) {
try {
const { code, userinfo } = yield call(loginReq, payload); localStorage.setItem('userinfo', JSON.stringify(userinfo));
// 触发reducers更新状态
// 犹如import { call, put, takeEvery } from 'redux-saga/effects'中的takeEvery
yield put({
type: 'init',
payload: userinfo,
});
history.push('/');
} catch (error) {
console.log(error);
}
},
},
reducers: {
init(state, action) {
// 将状态更新到state
return action.payload;
},
},
};

这里使用umi 就比较方便,不需要直接去进行redux-saga的操作,直接使用effects和reduces函数进行数据读取状态更新即可,而这里使用到了es6的generate 生成器函数,直接将异步当成同步来进行操作更加方便了

六、login

有了mock 和models 现在可以完善一下登录了,pages下创建login目录再在其下创建index.js,内容大概是这样子

import React, { Component } from 'react';
import styles from './index.css';
import ProForm, { ProFormText } from '@ant-design/pro-form';
import { UnlockOutlined, UserOutlined } from '@ant-design/icons';
import { connect } from 'dva';
const logo2 = require('../../../public/course/logo2.jpeg'); @connect()
class index extends Component {
onSubmit = (values) => {
if (values) {
this.props.dispatch({ type: 'user/login', payload: values });
}
};
render() {
return (
<div className={styles.loginForm}>
<ProForm
onFinish={(values) => this.onSubmit(values)}
submitter={{
searchConfig: {
submitText: '登录',
},
submitButtonProps: {
size: 'large',
style: {
width: '100%',
},
},
// 完全自定义整个区域
render: (_, dom) => dom.pop(),
}}
>
<h1
style={{
textAlign: 'center',
}}
>
<img className={styles.logo} alt="logo" src={logo2} />
</h1>
<div
style={{
marginTop: 12,
textAlign: 'center',
marginBottom: 40,
}}
>
WE USE ANTD DESIGN TO CREATE A LOGIN PAGE.
</div>
<ProFormText
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
name="username"
placeholder="admin"
rules={[
{
required: true,
message: '请输入用户名!',
},
]}
/>
<ProFormText.Password
fieldProps={{
size: 'large',
prefix: <UnlockOutlined />,
}}
name="password"
placeholder="123"
rules={[
{
required: true,
message: '请输入密码!',
},
]}
/>
</ProForm>
</div>
);
}
} export default index;

其中使用到了dva进行state 引入,使用dispatch 触发user/login 进行登录模拟操作,缓存用户信息,注意connect中有两个参数,第一个是

state,而state可根据models下面的文件中的namespace 调用不同的操作。第二个参数是一个对象 可以根据namespace映射对应的actions

@connect(
(state) => ({
loading: state.loading,
tags: state.goods.tags,
courses: state.goods.courses, // 获取goods 下的courses属性的值
userinfo: state.user, // 获取user 下对应的userinfo的值
}),
{
getList: () => ({
type: 'goods/getList',
}),
addCart: (payload) => ({
type: 'cart/addCart', // 映射cart文件中的addCart
payload, // 同时将payload 作为方法参数传入
}),
},
)

七、test

最后还有个商品列表页面,基本上套路和上面差不多,就不记了,最后测试哈

好了这个demo学习完毕,源码也提交到github保存下umi-dva-antd-react-demo

使用umi+dva做一个demo的更多相关文章

  1. 微软云创益大赛获奖团队风采:做一个中国特色的.Net源代码社区

    为了强化云技术,落地云应用,彰显云价值,微软(中国)携手中国计算机报举办了“微软Cloud OS第二届云创益大赛”.本届大赛历时111天,共吸引了6647位个人组选手回答了70,078道题,59支参赛 ...

  2. Umi + Dva的数据传递学习Demo(代码有详细注释)

    刚学习时写了篇笔记,以免自己忘记,用了一段时间后,觉得不如做个demo,代码写上注释,方便也在学习umi-dva的同学们理解更好,更容易上手. 这可能是网上注释最多,看了最易理解的学习小指南吧,哈哈. ...

  3. Hello log4net——做一个实用好用的log4net的demo(转)

    log4net使用指南  (对配置解释比较全面细致,建议做完demo后多看) Log4Net使用详解(周公)——点击打开链接 Log4Net使用详解(续)周公——点击打开链接 点击打开链接 点击打开链 ...

  4. 实战:一、使用mongo做一个注册的小demo

    思路:1.使用mongoose 进行 数据库的链接 2.使用Schema来进行传输字段的定义 3.安装koa-router进行数据处理4.安装koa-bodyparser 进行post数据交互5.解决 ...

  5. angular开发者吐槽react+redux的复杂:“一个demo证明你的开发效率低下”

    曾经看到一篇文章,写的是jquery开发者吐槽angular的复杂.作为一个angular开发者,我来吐槽一下react+redux的复杂. 例子 为了让大家看得舒服,我用最简单的一个demo来展示r ...

  6. 用javascript做一个视频播放器

    以前我们在网页上播放视频,都是要麻烦flash来实现.看着那一大段的<object>真心觉得累.随着html5的不断普及,现在是时候使用html5提供的video元素来做点正经事了,但是要 ...

  7. 初识nginx之第一个demo

    商城项目做了一个多月了,想到必须用到负载均衡,简单了解了一下nginx,首先分享第一个demo,五月份上线后,会继续分享一系列相关知识. 在nginx根目录下,用了一个园友的批处理文件nginx.ba ...

  8. 【Bugly干货分享】一起用 HTML5 Canvas 做一个简单又骚气的粒子引擎

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 前言 好吧,说是“粒子引擎”还是大言不 ...

  9. fir.im Weekly - 如何做一个出色的程序员

    做一个出色的程序员,困难而高尚.本期 fir.im Weekly 精选了一些实用的 iOS,Android 开发工具和源码分享,还有一些关于程序员的成长 Tips 和有意思有质量的线下活动~ How ...

  10. 使用React并做一个简单的to-do-list

    1. 前言 说到React,我从一年之前就开始试着了解并且看了相关的入门教程,而且还买过一本<React:引领未来的用户界面开发框架 >拜读.React的轻量组件化的思想及其virtual ...

随机推荐

  1. Android笔记--查询联系人

    查询联系人 先在raw_contacts表里面查到每个联系人的不同的id,然后再根据各个id去查询各个联系人的详细信息 然后利用id得到相应的uri的值: 之后,就直接根据uri查询各个联系人的详细信 ...

  2. K8S部署应用详解

    # 前言 首先以SpringBoot应用为例介绍一下k8s的发布步骤. 1.从代码仓库下载代码,比如GitLab:2.接着是进行打包,比如使用Maven:3.编写Dockerfile文件,把步骤2产生 ...

  3. 第六章 C控制语句:分支和跳转

    6.1if语句 程序 #define _CRT_SECURE_NO_WARNINGS 1 //coladays.c -- 求出温度低于零度的天数 #include<stdio.h> int ...

  4. 分布式缓存的一致性 Hash 算法

    一.使用一致性 Hash 算法的原因 简单的路由算法可以使用余数 Hash:用服务器数据除缓存数据 KEY 的 Hash 值,余数为服务器列表下标编码.这种算法可以满足大多数的缓存路由需求.但是,当分 ...

  5. openwrt 刷回梅林或者原厂固件

    路由器刷了openwrt固件后,访问不了CFE恢复模式了.本人最近用腾达AC18路由器,刷了AC68U的梅林改版固件.但是后面再用CFE刷了openwrt固件之后,发现wifi不能用,所以又想刷回梅林 ...

  6. 通知短信 API 接入全流程(超详细整理)

    随着移动互联网和智能手机的普及,短信成为了一种便捷.快速且有效的通信方式,尤其在向用户发送重要信息或提醒方面具有很大的优势. 本文将会深入探讨如何在程序中接入通知短信 API 实现短信通知功能,此外, ...

  7. 面试题锦集:1、数据库三大范式,2、mysql索引类型及作用,3、事务的特性和隔离级别

    目录 面试题集锦 一.数据库三大范式 二.mysql有哪些索引类型及作用 三.事务的特性和隔离级别 1.事务的四大特性 2.事务的隔离级别 3.什么是脏读.不可重复度.幻读 4.解决办法 面试题集锦 ...

  8. Flask快速入门day02(1、CBV使用及源码分析,2、模板用法,3、请求与响应的基本用法,4、session的使用及源码分析,5、闪现,6、请求扩展)

    目录 Flask框架 一.CBV分析 1.CBV编写视图类方法 二.CBV源码分析 1.CBV源码问题 2.补充问题 3.总结 三.模板 1.py文件 2.html页面 四.请求与响应 1.reque ...

  9. 部署kubernetes官网博客

    部署kubernetes官网博客 访问 https://kubernetes.io/ 有些时候不问题,部署离线内网使用官网以及博客, 各位尝鲜可以访问 https://doc.oiox.cn/ 安装d ...

  10. [设计模式/网络/WebServer/Nginx]设计模式之代理模式(网络代理 : 正向代理与反向代理)【7】

    1 代理模式 1.1 模式定义 代理模式(Proxy Pattern):为其他对象提供一种代理服务以对这个被代理的对象进行控制访问.[ 设计模式.面向对象程序设计思想的鼻祖----GoF] Subje ...