先说些废话

最近在开发React技术栈的项目产品,对于数据状态的管理使用了Dva.js,作为一个资深的ow玩家,我看到这个名字第一反应就是————这不是ow里的一个女英雄吗?仔细阅读了官方文档之后,发现开发者还真是因为这个角色获得灵感,来命名这个数据状态管理插件,果然开发大佬都是工作和休闲两不误~

学过React的同学都知道它的技术栈非常多且杂,所以每当你使用React的时候都需要引入很多的模块,那么Dva就是把这些用到的模块集成在一起,比如一些需要引入的依赖react-saga/react-loger、必写的ReactDOM.renderprovider、connect包裹等都省去不写,形成一定的架构规范,大大提高我们的开发效率

今天,就来写一份文档,帮助后续使用Dva的开发者更好得在实际项目中(PS:需要是以UMI为基础框架,纯Dva来构建项目可以直接看文章结尾的参考文档列表)上手使用

什么是Dva

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

在我目前的项目中,更多是使用数据状态管理的功能,他在我司的fish框架中做了内嵌,在主流的React开发框架UMI中也做了内嵌适配,使用起来非常方便快速。

Dva设计的目的就是简化元素,降低难度,让你不用管他怎么实现的,我们按照默认的这个规则去写就可以

数据流向

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过dispatch发起一个action,如果是同步行为会直接通过reducers改变states,如果是异步行为(副作用)会先触发effects然后流向reducers最终改变states

分层开发

无论是Vue还是React开发,实际的大型应用一定有严格的分层开发规范,确保后续开发的可维护性,主要的分层结构有以下几点:

  • Page 负责与用户直接打交道:渲染页面,接受用户的操作输入,侧重于展示型交互性逻辑,这里需要了解无状态组件
  • Model 负责处理业务逻辑,为 Page 做数据、状态的读写、变换、暂存等,Dvamodel就是做了这一层的操作
  • Service 负责与 HTTP 接口对接,进行纯粹的数据读写

基础概念

  1. namespace

    • model的命名空间,同时也是他在全局state上的属性
    • 只能用字符串,不支持通过.的方式创建多层命名空间,相当于这个modelkey
    • 在组件里面,通过connect这个key将想要引入的model加入
    import { connect } from 'dva';
    export default connect(({ namespaceValue }) => ({ ...namespaceValue }))(DvaCompoent);
  2. state
    • 表示model的状态数据
    • 操作的时候每次都要当作不可变数据immutable data来对待,保证每次都是全新对象,没有引用关系
  3. reducer
    • 必须是纯函数,有固定输入输出,主要目的是修改自身state
    • 接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果,该函数把一个集合归并成一个单值
    • 需要注意的是同样的输入必然得到同样的输出,它们不应该产生任何副作用effect。并且,每一次的计算都应该使用immutable data
  4. effect
    • 主要用于异步请求,接口调用之类的
    • effect被称为副作用,在我们的应用中,最常见的就是异步操作
    • 它来自于函数编程的概念,之所以叫副作用是因为它使得我们的函数变得不纯,同样的输入不一定获得同样的输出
  5. subscription
    • subscription语义是订阅,用于订阅一个数据源,然后根据条件dispatch需要的action
    • 数据源可以是当前的时间、服务器的websocket连接、keyboard输入、geolocation变化、history路由变化等等
    • 内部定义的函数都会被被执行,执行之后作为监听来处理事务
  6. dispatch
    • dispatch是一个用于触发action的函数,action是改变state的唯一途径,但是它只描述了一个行为,而dipatch可以看作是触发这个行为的方式,reducer则是描述如何改变数据的
    • Dva中,connect model的组件通过props可以访问到dispatch,可以调用model中的reducer或者effects
    import { connect } from 'dva';
    const testCom = props => {
    const { dispatch } = props;
    const changeValue = (id, val) => {
    // 调用reducer,一般是同步修改state中的值
    dispatch({
    type: 'dva/save',
    payload: {
    param: val
    },
    });
    // 调用effect,一般是发送后台请求
    dispatch({
    type: 'dva/queryValue',
    payload: {
    id: id
    },
    });
    };
    return(
    <div>'hello world'</div>
    )
    }
    export default connect(({ dva }) => ({ ...dva }))(testCom);

Model中的Effects函数解析

需要注意的是:Effects里面的函数都是Generator函数

  1. yield

    • 固定关键词,Generator函数自带的关键词,和*搭配使用,有点像asyncawait,使用*则表明它是Generator函数
    • 然后每使用一个yield就是告诉程序这里是异步,需要等待这个后面的代码执行完成,同步代码可不使用该关键词
  2. payload
    • 页面上通过dispatch传过来的payload同名参数
  3. select
    • DvaEffects函数的固定传参
    • 用于拿到modelstate的数据,需要注意的是,state后面跟命名空间namespace的值
    const data = yield select((state) => state.namespaceName.valueName);
  4. call
    • DvaEffects函数的固定传参
    • 第一个参数是一个异步函数,payload是参数,可以通过call来执行一个完整的异步请求,又因为yield的存在,就实现了异步转同步的方案
    const { data } = yield call(queryInterface, payload);
  5. put
    • DvaEffects函数的固定传参
    • 可以使用同model中的Reducers或者Effects,通过Reducers来实现数据到页面的更新,也可以通过put实现Effects的嵌套使用
    yield put({
    type: 'save',
    payload: {
    ...payload
    },
    });

开发目录

由于公司的fish框架以及常见的umi框架都对Dva做了深度继承,会默认将src/models下的model定义自动挂载,只需要在model文件夹中新建文件即可新增一个model用来管理组件状态,对于某个page文件夹下面的model也会默认挂载

├─assets `静态资源`
├─components `公共组件`
├─config `路由和环境配置`
├─constants `全局静态常量`
├─locale `国际化`
│ ├─en_US `英文配置`
│ └─zh_CN `中文配置`
├─models `全局数据状态` *Dva涉及的目录*
├─pages `页面目录,用我参与开发的其中一个目录来作为示例` *Dva涉及的目录*
│ ├─NodeConfig `NodeConfig示例目录`
│ │ ├─components
│ │ │ ├─Select `Select组件页面文件` *Dva涉及的目录*
│ │ │ │ └─components
│ │ │ │ ├─AudienceInfo
│ │ │ │ │ ├─index.js
│ │ │ │ │ └─index.less
│ │ │ │ ├─BlackList
│ │ │ │ │ ├─index.js
│ │ │ │ │ └─index.less
│ │ │ │ ├─ControlGroup
│ │ │ │ │ ├─index.js
│ │ │ │ │ └─index.less
│ │ │ │ └─GroupSelect
│ │ │ │ │ ├─index.js
│ │ │ │ │ └─index.less
│ │ │ │ ├─index.js
│ │ │ │ └─index.less
│ │ ├─models
│ │ │ ├─select.js `Select组件数据状态管理` *Dva涉及的目录*
│ │ └─services
├─services `全局接口配置`
├─themes `全局样式主题`
└─utils `js通用工具` PS: 该树形图通过 `windows shell` 自带的 `tree` 命令生成

如何使用Dva

首先定义一个简易的model示例

export default {
namespace: 'dva',
state: {
id: '',
value: {},
},
effects: {
// 所有effect前必须要加 *
*queryValue({ payload }, { select, call, put }) {
const params = {
id: payload.id ? payload.id : yield select(state => state.select.id)
}
const { data } = yield call(queryInterface, params); // queryInterface是定义好的后台请求接口,一般用axios或fetch来完成
yield put({ type: 'save', payload: data });
},
},
reducers: {
save(state, { payload }) {
return {
...state,
...payload,
};
},
},
subscriptions: {
keyboardWatcher({ dispatch }) {
key('⌘+up, ctrl+up', () => { dispatch( {type:'save'}) });
},
},
};

然后把model和组件绑定在一起

React的Connect函数是一种柯里化写法

import { connect } from 'dva';

const testCom = props => {
const { helloWorld = 'hello world'} = props;
return(
<div>{ helloWorld }</div>
)
} // 绑定之后就可以在testCom组件中使用命名为dva的model了
export default connect(({ dva }) => ({ ...dva }))(testCom);

柯里化

柯里化是把接受多个参数的函数转换成接受一个单一参数的函数(PS:Scala语言中也有类似的设计)

// 柯里化
var foo = function(x) {
return function(y) {
return x + y
}
}
foo(3)(4) // 普通方法
var add = function(x, y) {
return x + y;
}
add(3, 4)

无状态组件

创建无状态组件是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到要改变state状态的操作,

在实际项目中页面组件被写成无状态的组件,通过简单组合可以构建成页面或复杂组件,通过多个简单组件来合并成一个复杂的大应用

const NoStateComponent = props => {
const { helloWorld = 'hello world'} = props;
return(
<div>{ helloWorld }</div>
)
}
export default NoStateComponent;

无状态组件的优点

  1. 由于是无状态组件,所以无状态组件就不会在有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升
  2. 代码整洁、可读性高,对于大型项目的开发维护非常有好处

参考文档一 ———— Dva官方文档

参考文档二 ———— UMI官方文档

参考文档三 ———— REACT基础笔记 MODEL分层

参考文档四 ———— 前端数据流方案Dva

参考文档五 ———— 浅析dva (史上最全的dva用法及分析)

参考文档六 ———— 【dva】model中effects函数的解析

参考文档七 ———— Generator 函数的详解

参考文档八 ———— React connect()() 双括号 --柯里化写法

参考文档九 ———— 高级函数技巧-函数柯里化

我是 fx67ll.com,如果您发现本文有什么错误,欢迎在评论区讨论指正,感谢您的阅读!

如果您喜欢这篇文章,欢迎访问我的 本文github仓库地址,为我点一颗Star,Thanks~

转发请注明参考文章地址,非常感谢!!!

Dva.js 快速上手指南的更多相关文章

  1. Rancher 快速上手指南操作(1)

    Rancher 快速上手指南操作(1)该指南知道用户如何快速的部署Rancher Server 管理容器.前提是假设你的机器已经安装好docker了.1 确认 docker 的版本,下面是 ubunt ...

  2. UnityShader快速上手指南(三)

    简介 这一篇还是一些基本的shader操作:裁剪.透明和法向量的应用 (纠结了很久写不写这些,因为代码很简单,主要是些概念上的东西) 先来看下大概的效果图:(从左到右依次是裁剪,透明,加了法向量的透明 ...

  3. [转]Rancher 快速上手指南操作(1)

    本文转自:http://www.cppblog.com/zhiyewang/archive/2016/03/17/213053.aspx Rancher 快速上手指南操作(1)该指南知道用户如何快速的 ...

  4. Markdown快速上手指南

    Markdown快速上手指南 1.Markdown介绍 markdown可以实现快速html文档编辑,格式优没,并且不需要使用html元素. markdown采用普通文本的形式,例如读书笔记等易于使用 ...

  5. Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so)

    本文首发于 Ficow Shen's Blog,原文地址: Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so). 内容概览 前言 ...

  6. Github Action 快速上手指南

    前言 各位读者,新年快乐,我是过了年匆忙赶回上海努力搬砖的蛮三刀. Github之前更新了一个Action功能(应该是很久以前了),可以实现很多自动化操作.用来替代用户自己设置的自动化脚本(比如:钩子 ...

  7. UnityShader快速上手指南(二)

    简介 前一篇介绍了如果编写最基本的shader,接下来本文将会简单的深入一下,我们先来看下效果吧 呃,gif效果不好,实际效果是很平滑的动态过渡 实现思路 1.首先我们要实现一个彩色方块 2.让色彩动 ...

  8. UnityShader快速上手指南(一)

    简介 引言 其实网上有很多shader教程,但是大概看了下,也不知是网上各位大神已经脱离了代码层面的高度还是啥原因.貌似没有找到从代码方面作为入门讲解的,导致了shader对于苦逼程序员入门有一定要求 ...

  9. Mac快速上手指南

    上周刚入手了2017版MacBookPro,预装macOS High Sierra.第一次接触Mac系统,经过一周的使用,简单总结下与Windows相比最常用的功能,快速上手. 1.Mac键盘实现Ho ...

  10. IDEA 快速上手指南(全配置)(Day_23)

    Idea快速入门指南 1.安装 1.1.安装 我们使用的是2017.3.4版本: 双击打开, 选择一个目录,最好不要中文和空格: 然后选择桌面快捷方式,请选择64位: 然后选择安装: 开始安装: 然后 ...

随机推荐

  1. CF-938(C-E)

    CF-938 C 没啥好分析的,就记录一下我因为没有清空s[n+1].上取整写成了下取整卡了一个多小时(╬▔皿▔)╯ const int N=2e5+5; int a[N],p[N],s[N]; vo ...

  2. 轻松复现一张AI图片

    轻松复现一张AI图片 现在有一个非常漂亮的AI图片,你是不是想知道他是怎么生成的? 今天我会交给大家三种方法,学会了,什么图都可以手到擒来了. 需要的软件 在本教程中,我们将使用AUTOMATIC11 ...

  3. 力扣167(java&python)-两数之和 II - 输入有序数组(中等)

    题目: 给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数.如果设这两个数分别是 numbers[in ...

  4. Apsara Stack 技术百科 | 浅谈阿里云混合云新一代运维平台演进与实践

    ​简介:随着企业业务规模扩大和复杂化及云计算.大数据等技术的不断发展,大量传统企业希望用上云来加速其数字化转型,以获得虚拟化.软件化.服务化.平台化的红利.在这个过程中,因为软件资产规模持续增大而导致 ...

  5. Flink集成Iceberg在同程艺龙的实践

    ------------恢复内容开始------------ null ------------恢复内容结束------------

  6. 函数计算 GB 镜像秒级启动:下一代软硬件架构协同优化揭秘

    ​简介:本文将介绍借助函数计算下一代 IaaS 底座神龙裸金属和安全容器,进一步降低绝对延迟且能够大幅降低冷启动频率. 作者:修踪 背景 函数计算在 2020 年 8 月创新地提供了容器镜像的函数部署 ...

  7. WPF 使用 VisualBrush 在 4k 加 200 DPI 设备上某些文本不渲染看不见问题

    这是我做一个十万点实时刷新的图表控件遇到的问题,做过高性能图表的伙伴大概都知道,此时需要关闭命中测试的功能,无论是控件的还是 Drawing 的,否则计算命中测试的耗时将会让主线程卡住.为了解决此问题 ...

  8. WPF 下拉框选项做鼠标 Hover 预览效果

    本文来告诉大家如何在 WPF 中,在 下拉框 ComboBox 里面,鼠标移动到 ComboBoxItem 上时,自动触发对应的事件,用来预览此选项值.例如我在实现一个颜色下拉框,此时我可以通过点击下 ...

  9. openpyxl模块操作Excel

    1.openpyxl模块了解 1.excel版本问题 03版本之前的excel文件后缀名xls 03版本之后的excel文件后缀名xlsx 2.python操作excel表格的模块 openpyxl ...

  10. 第一章 Jenkins安装配置

    Jenkins官网 # 官网: https://www.jenkins.iohttps://www.jenkins.io/zh/ # docker安装: https://www.jenkins.io/ ...