前言

本示例依照Ant Design 实战教程(beta 版)进行编写,非常感谢各位大佬的倾情付出!谢谢

正是江南好风景,落花时节学代码

春暖花开,写一个React小Demo,典型SPA项目_经验分享

有了前两节的铺垫,这个Ant Design 实战教程(beta 版)也觉得挺顺手的,汇总下编写的流程以及接下来要进一步学习的内容。

第一部分:整体概述

该demo是个典型的SPA项目,实现功能如布局、侧边栏、列表、表格、弹窗等,其中包含:

  • 应用框架:Umi

  • 数据流:DvaJs

  • UI: Antd

Umi,中文可发音为乌米, 是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。


DvaJs首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。


Antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。


hhw-4:antd-course hhw$ tree -L 4 -I node_modules
.
├── config #配置文件
│ └── config.js
├── dist
│ ├── index.html
│ └── umi.js
├── mock
│ └── articleMock.js
├── package.json
└── src
├── layout
│ └── index.js
├── models
│ ├── articleModel.js
│ ├── chartModel.js
│ └── complexArticleModel.js
├── pages
│ ├── Chart
│ │ └── ChartClass.js
│ ├── Complex
│ │ ├── Article.js
│ │ └── ComplexArticle.js
│ ├── Dashboard
│ │ ├── Analysis.js
│ │ ├── Monitor.js
│ │ └── Workplace.js
│ └── HelloWorld.js
├── service
│ └── chart.js
└── util
└── request.js

第二部分
一、DvaJs--Effect

Reducer如果做了异步操作,将破坏redux中reducer是纯函数的机制,effect 就是专门处理这些具有 "副作用" 的操作的执行单元。

export default {
namespace: 'some_namespace',
state: {},
effects: { // 定义 effects 成员
'someEffect': function*() {},
'someOtherEffect': function*() {},
// ...
},
reducers: {
// ...
},
}
  • 宏观上看,effect 是一层中间件。

  • 局部上看 effect 就是一个一个的 generator function。

1、中间层

什么是中间层?

" Middleware is some code you can put between the framework receiving a request, and the framework generating a response. "

当 action 被 dispatch 之后,会先到达 effect 处理副作用,然后该 effect 最终会促使新的 action 发送出去,这个新的 action 可能被其他的 effect 再捕获继续处理,也可能被 reducer 捕获并结束,无论怎样,最终处理逻辑的终点都将是 reducer。

2、 generator function

春暖花开,写一个React小Demo,典型SPA项目_经验分享_02

异步的实质是事件发生促使程序的执行点来回跳转。我们使用 callback 本质上是描述跳转的一种手段。generator function 并没有改变异步的本质,只是改变了描述的方式,使得程序看起来像是同步一样。

一个 generator function 在执行时有 两方。一方是 generator function 本身,另一方是 generator function 的句柄持有者,而这一般都是框架所持有。我们姑且称这个句柄为 genStub。当框架调用 genStub.next() 时,generator function 会执行到下一个 yield 然后暂停,并把 yield 后面表达式的计算值返还给框架,同时把程序执行权交给框架。框架拿到值后做处理,比如就是异步处理,处理结束拿到结果,再次调用 genStub.next(),返还值给 generator function 同时驱动它恢复执行。当恢复执行时,你可以认为 返回的处理结果会整体替换 yield <expression>,然后程序继续执行到下一个 yield。

yield 这个单词用在这里特别形象:yield 本身有「让步」的意思,也有「产出」的意思。

「generator function yield 到外部的值」和「外部返还给 generator function 的值」不是一回事!!!

3、使用

入参有两个对象,第一个对象就是匹配这个 effect 的 action 对象,因此可以取到约定的 payload 这个字段,第二个对象是 effect 原语集,其中 call, put 最为常用,

call: 阻塞 用于调用异步逻辑,支持 promise
put: 不阻塞 用于触发 action,一般来触发reducer改变state
select: 不阻塞 用于从 state 里获取数据
take: 阻塞 dva封装了take,可以监听action的开始和结束阶段,take会阻塞到监听的事件触发,才执行下一步

示例

春暖花开,写一个React小Demo,典型SPA项目_经验分享_03

二、代理

在前端开发中,一种常见的规避跨域的方法就是:把 ajax 请求发送到你的本地开发服务器,然后本地开发服务器再把 ajax 请求转发到远端去,从网络拓扑上看本地开发服务器起着「反向代理」的作用。本地服务器和远端服务器是「服务器和服务器间的通信」,就不存在跨域问题了。

配置代理也很简单,只需要您在配置文件 config/config.js 中与 routes 同级处增加 proxy 字段,代码如下,

+  proxy: {
+ '/dev': {
+ target: 'https://08ad1pao69.execute-api.us-east-1.amazonaws.com',
+ changeOrigin: true,
+ },
+ },

配置的含义是:去往本地服务器 localhost:8000 的 ajax 调用中,如果是以 /dev 开头的,那么就转发到远端的 https://08ad1pao69.execute-api.us-east-1.amazonaws.com 服务器当中,/dev 也会保留在转发地址中。

春暖花开,写一个React小Demo,典型SPA项目_经验分享_04

三、二次封装

Antd真的很赞!对于开发者而言,公共的代码其实可以二次封装一下,比如from表单等,可以减少不少的代码。

四、CSS Modules

春暖花开,写一个React小Demo,典型SPA项目_经验分享_05

CSS Modules 详解及 React 中实践

CSS MODULES用法教程

CSS modules 将生成全局唯一的hash值【标签实际的class】。通过全局唯一的class name 变相的就可以获取到局部作用域【scoped css】,如果一个 CSS 文件仅仅是作用在某个局部的话,我们称这样一个 CSS 文件为 CSS module。

注意:很多 CSS 选择器是不会被 CSS Modules 处理的,比如 body、div 、a 这样的 HTML 标签名就不会。我们推荐如果要定义局部 css 样式/动画, 只使用 class 或 @keyframe。

Less 官方文档

Less 是一个 CSS 的超集,Less 允许我们定义变量,使用嵌套式声明,定义函数等。严格说 Less 包含两部分:1. Less 的语法。2. Less 预处理器(Less preprocessor)。浏览器终究只认识 CSS,所以 Less 文件需要经过 Less 预处理器编译成为 CSS。


在工具的支持下,一个 Less 文件首先会经过 CSS modules 的编译,把类名全局唯一化,然后才被 Less preprocessor 编译成为 CSS 文件。正因此,Less 文件可以和 CSS modules 无缝联合使用。


// less 文件
// 常量
@grey-color: rgba(0, 0, 0, 0.25);
// 类嵌套
.hello {
font-size: 32px;
font-weight: bold;
color: #30b767;
.deleted {
text-decoration: line-through;
background-color: @grey-color;
}
}

// 重写Antd样式
.override-ant-btn {
// CSS Modules 允许使用:global(.className)的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。
:global(.ant-btn) {
border-radius: 16px;
}
}
          <div>
<div className={commonStyles.hello}> css module </div>
<div className={lessStyles.hello}>
<span className={lessStyles.deleted}>Less class 嵌套</span>
</div>
<div>
<p>
<span className={lessStyles['override-ant-btn']}>
<Button>圆角样式按妞</Button>
</span>
</p>
<p>
<Button>antd 原始按钮</Button>
</p>
</div>
</div>

春暖花开,写一个React小Demo,典型SPA项目_经验分享_06


最后强调,global 不应该被滥用,特别地我们建议:若想在某个文件中覆盖 antd 样式,请加上一个类似 .override-ant-btn 的类包裹住 global 修饰的名称,以避免全局样式声明分散在项目各处。

还有很多待补充的内容,边做边学