看其他的看的一头雾水,找到一篇比较清晰的 Dva.js 入门级教学文档

原文https://zhuanlan.zhihu.com/p/91136946?utm_source=wechat_session

Dva.js 入门级教学文档 总体介绍本文的框架

一、介绍
二、环境搭建和使用
三、全局架构
四、Model 包下文件架构
五、connect 连接 Model 和 Route 页面下的数据
六、初始化数据 和 Model 数据比对
七、数据显示和操作的流程
八、稍复杂概念
一、介绍
1、什么是 dva
React 应用级框架,将 React-Router + Redux + Redux-saga 三个 React 工具库包装在一起,简化了 API,让开发 React 应用更加方便和快捷

简单理解:dva = React-Router + Redux + Redux-saga

2、dva 的作用是什么
二、环境搭建和使用
1、环境搭建
$ npm install dva-cli -g
$ dva -v //查看下是否安装成功,显示 dva 的版本号
dva-cli version 0.9.1
2、创建项目
$ dva new dva-1 //dva-1 为你创建项目的名称
安装成功后,cd 进入 dva-1 目录下,通过 npm start 和 yarn start 启动项目

如果启动报错的话,可以先执行 npm i 或者 yarn

3、使用 antd
在进入到项目目录下后,输入如下命令:

$ npm install antd babel-plugin-import --save
通过 npm 安装 antd 和 babel-plugin-import。babel-plugin-import 是用来按需加载 antd 的脚本和样式的。

注意!!!

请在全局目录下找到 .webpackrc 文件,输入以下代码,使 babel-plugin-import 插件生效。

{

  • “extraBabelPlugins”: [
  • [“import”, { “libraryName”: “antd”, “libraryDirectory”: “es”, “style”: “css” }]
  • ]
    }
    再次强调:注意上面的插件生效的代码,不输入以上代码,按需加载 antd 插件不生效

三、全局架构
.
├── mock // mock数据文件夹
├── node_modules // 第三方的依赖
├── public // 存放公共public文件的文件夹
├── src // 最重要的文件夹,编写代码都在这个文件夹下
│ ├── assets // 可以放图片等公共资源
│ ├── components // 就是react中的木偶组件
│ ├── models // dva最重要的文件夹,所有的数据交互及逻辑都写在这里
│ ├── routes // 就是react中的智能组件,不要被文件夹名字误导。
│ ├── services // 放请求借口方法的文件夹
│ ├── utils // 自己的工具方法可以放在这边
│ ├── index.css // 入口文件样式
│ ├── index.ejs // ejs模板引擎
│ ├── index.js // 入口文件
│ └── router.js // 项目的路由文件
├── .eslintrc // bower安装目录的配置
├── .editorconfig // 保证代码在不同编辑器可视化的工具
├── .gitignore // git上传时忽略的文件
├── .roadhogrc.js // 项目的配置文件,配置接口转发,css_module等都在这边。
├── .roadhogrc.mock.js // 项目的配置文件
└── package.json // 当前整一个项目的依赖
1、index.js(重点)
import dva from ‘dva’;

// 1、创建 dva 实例
const app = dva();

// 2、装载插件 (可选)
app.use(require(‘dva-loading’)());

// 3、注册 Model
app.model(require(’./models/example’));

// 4、配置路由
app.router(require(’./router’));

// 5、启动应用
app.start(’#root’);
通过上面的代码块,应该就可以很清楚了了解到 Dva 的5个 API

如果还不清楚,没关系,下面我一一讲解:

(1)、创建 dva 实例
用于创建应用,返回 dva 实例,dva 支持多实例,如:

const app = dva({
history,
initialState,
onError,
onAction,
onStateChange,
onReducer,
onEffect,
onHmr,
extraReducers,
extraEnhancers,
});
但是鉴于我只用过 initialState,就拿 initialState 来说。

initialState 为初始化数据,后面会讲解它和 model 中 state 的区别。大家可以在留心观看哈。

每个页面初始化的数据都将放在这里。并且 initialState 对象下的命名方式为:每个 model 的 namespce

如果命名不规范,数据是初始化不到页面上的。

(2)、装载插件
需要任何样式的插件以上面的形式编写代码即可。

如果不需要任何插件,这段代码都可以直接省略。

上面引用的插件是:页面还未加载完毕时显示的 loading 图标,加上了上面那行插件代码,你就不要每个页面都写 showloading 和 hideloading 了。

(3)、注册 Model
你每创建出来的一个 model 都需要来全局 index.js 来注册一下,这样 model 层才能用。

Model 层的代码是重点,会放到下面的第四大点重点讲解。这里只是告诉大家要注册一下。

(4)、配置路由
细心的小伙伴会发现在 index.js 同级目录下有一个 router.js,这里的配置路由就是配置这个页面的东西。下面第2小点马上就讲解,这里只是告诉大家,如何引用配置好的路由。

(5)、启动应用
启动应用不解释。

2、router.js
打开 router.js 你就看到如下的代码:

import IndexPage from ‘./routes/IndexPage’;
import HomePage from ‘./routes/HomePage’;

. . . 使用 我们每创建出来的一个页面,都需要在这里配置路由。

path:为页面的路径名称,注意:要加上前缀斜杠。命名可以随意,不过一般以创建页面的名字命名,这样比较清楚。

component:为代码最上方导入的页面。

上面我写了一个 home 页面的例子,供大家参考。

解释一下
每个路由器都会创建一个 history 对象,并用其保持追踪当前 location 并在有变化的时候进行重新渲染。

location:是一个含有描述 URL 不同部分属性的对象。

来看一下 Dva官网的解释:这里的路由通常指的是前端路由,由于我们的应用现在通常是单页应用,所以我们需要前端代码来控制路由逻辑,同茶馆浏览器提供的 History API可以监听浏览器url的变化,从而控制路由相关操作。

dva 使用的是 react-router 来控制路由。

小伙伴们如果想深入学习路由这块的内容可以找度娘搜索:react router 学习哈。

3、components 包
一般为我们创建出来的公共组件。

4、routes 包
这里我们可以理解为 pages。你所要显示出来的页面都写在这个下面。

5、services 包
为后台调用服务端接口的包,不做解释。

6、utils 包
这个包可以用来存放一些公共方法。需要使用时,导入 js,直接使用方法即可。

6、models 包
models 包用来存放 所有的 model 文件。

一个完整的 model 文件的架构:

export defalut {
namespace:’’,
state:{},
reducers:{},
effects:{},
subscriptions:{},
}
好了。马上进入我们的 Model 文件结构专题。

四、Model 包下文件架构(重点)
1、namespace
官网解释:当前 Model 的名称。整个应用的 State,由多个 Model 的 State 以 namespace 为 key 合成的。

官网解释很绕,通俗的说:就是给每个 Model 一个命名用作 key 的标识。一般命名方式等于 Model js 的 文件名,举个例子:

Model 文件 home.js 里 namespace 值可以设为:home

2、state
该 Model 当前的状态。每个 Model 的数据都保存在这里,这里的数据通过 Route 视图层的 this.props,直接显示在页面上。

这里的数据一改变,页面上的数据也将自动改变。

3、reducers
用来处理同步操作。如果不需要调接口时候,我们前台传递的 action(不懂的小伙伴不着急,下面有微讲解) 可以直接调用 reducers 里的方法。

上面说的同步是同步什么呢?同步该 Model 里面的 state 的数据。

打开项目中 models example.js。找到 reducers,我将他复制在下方,来讲解一下怎么创建 reducers 下的方法。

reducers: {
save1(state, action) {
return { …state, …action.payload };
},
save2(state, action) {
return { …state, …action.payload };
},
},
(1)、save
save:为一个普通方法的命名,可自行取名

(2)、state
state:为当前 Model 下的所有 state 值,可以 console.log(state) 看一下输出就知道了。

(3)、action
action:当前台页面需要进行数据操作时,就会创建一个 action,action 存放了传递过来需要对当前 state 进行改变的数据。

(4)、payload
payload:就是 action 里传递过来的数据。可以 console.log(action.payload) 看一下输出就知道了。

(5)、return
return:返回的是新的 state。等于舍弃了旧的 state,重新 return 一个新的 state 作为当前 Model 的 state。

一般情况下,我们要解开旧的 state,将它重新赋值给新的 state。…state 为 ES6 语法。

将操作完成得数据累加到 return 中。

同名的数据会覆盖,所以不用担心旧的 state 值会影响到新设置的值。

不同名的数据会追加。

4、effects
用来处理异步操作。如果需要调取接口的话,前台页面就需要调用 effects 里的方法。

将数据取出来,在传递给 reducers 里的方法进行数据操作和同步 state。

来看看例子:

import { querySomething } from ‘@/services/api’;

query({ payload }, { call, put, select }) {
const data = yield call(querySomething, payload);
console.log(data)
yield put({
type: ‘save1’,
payload: { name: data.text },
});
},
(1)、

*:这个 * 符号,可能小伙伴们不熟悉,简单点,不管它,只要记住每个 effects 里方法前面都加上 * 即可。

稍微解释一下:

这表明它是一个异步函数,里面可以使用 yield 等待其他异步函数执行结果。

(2)、query
query:方法名,自定义命名。不多解释。

(3)、payload
payload:当前台页面需要进行数据操作时,就会创建一个 action,action 存放了传递过来需要对当前 state 进行改变的数据。

payload 就是存放在 action 里面的数据。可以 console.log(payload) 看输出的效果。

(4)、call
call:与后台服务端接口进行交互。

第一个传参:后台服务器接口对应的名称。第二个参数:入参。

同行的 data 为出参。可以 console.log(data) 看输出的效果。

(5)、put
put:用来发出事件,即 action。一般调用 reducers 下的方法进行同步数据。

type:该 Model 层里 reducers 下的方法名。

payload:参数的传递。

如此一来。我们就将服务端查出来的数据,传递给 reducers 进行同步数据的操作了。

(6)、select
select:如果我们需要调用到其他 Model 层里面的 state值。那么我们就需要用 select 来进行操作。

const homeName = yield select(state => state.home);
这样我们就可以取到名为 home 的 Model 层里面的 state 数据了。

(5)、subscription
Model 中的 subscription 相当于一个监听器,可以监听路由的变化、鼠标、键盘、服务器连接变化等。

这样再其中可以根据不同的变化作出相应的处理。

如果你只是入门级别的选手,其实不需要用到这个东西,我自己也没用过,放个例子你们看看。

subscriptions: {
setup:({ dispatch, history }) {
window.onresize = () => { //这里表示的当浏览器的页面的大小变化时就会触发里面的dispatch方法,这里的save就是reducers中的方法名
dispatch (type:“save”)
}
},
onClick ({dispatch}) {
document.addEventListener(‘click’,() => { //这里表示当鼠标点击时就会触发里面的dispatch命令,这里的save就是reducers中的方法名
dispatch (type:“save”)
})
}
五、connect 连接 Model 和 Route 页面下的数据
dva 有提供 connect 方法。只要在每个 Routes 页面导入下面的代码即可。

import { connect } from ‘dva’;
如果细心的小伙伴已经发现了,Routes 下的页面定义的都是状态组件,而不是用 class ~ extends React.Components,这样的好处是:组件不被实例化,整体渲染性得到了提升。

对于组件:

我们在最后导出时使用 connect 进行与 Models 的连接。

export default connect(({index}) => ({index}))(IndexPage);
解释一下 index:

index 为 Model 层里面的 namespace。只要补上上面的代码就可以了。是不是很快~

六、初始化数据 和 Model 数据比对
1、初始化数据
这里指的是全局 index.js 里的 initialState,大家可以参考 第三大点->第1小点下:创建 dva 实例

这里存放的是一个个以 model 下的 namespace 命名的对象;如果你随意命名的化页面是找不到你存放在这里的数据的。

2、Model -> state
这里也是用来存放数据对象的。

两者的对比是:initialState 的优先级会高于 model => state,默认是 {},所以页面初始化时,读取到的数据是 initialState。

七、数据显示和操作的流程
接下来我将用最简单的步骤从无到有的演示一遍 dva 的写法和数据传输的流向。

不要看有那么多的步骤,其实每一步都很简短,很简单。

1、编写 Route 页面
class 的写法就是 class ~ extends React.Component{}

这里我将用组件的形式演示一遍。

import React from ‘react’;

const Example = ({dispatch,全局 index.js 里你需要的参数对象名称}) => {
return (

)
}

export default Example;
这就是一个最简单的页面。

2、编写 Model 层代码
export default {

namespace: ‘example’,

state: {},

effects: {
*fetch({ payload }, { call, put }) { // eslint-disable-line
yield put({ type: ‘save’,payload:data });
},
},

reducers: {
save(state, action) {
return { …state, …action.payload };
},
},
};
也是最简单的 Model 的格式,有任何不懂得地方请直接参考第四大点。

3、编写 初始化数据
在全局 index.js 里 修改下面这段代码:

const app = dva({
initialState: {
example: {
name:‘nameText’
}
}
})

app.model(require(’./models/example’).default); //还要记得补上这句话。在 index.js 里载入它。
4、修改路由配置
import Count from ‘./routes/Example’;

5、使用 connect 连接 在 Route -> example.js 页面上使用 connect。

修改代码:

import { connect } from ‘dva’;

export default connect(({ example }) => ({ example }))(Example);
如此一来,在页面上通过 this.props 即可获取到 example 里得数据。

6、前台调用 Model 层方法
如果需要于后台交互,那么就需要将入参传递到后台的 Model 层进行服务器的交互。

这里距需要讲解一下 dispatch了。

dispatch:是一个用于触发 action(这里可以直接理解为:调用后台的 model 里的方法) 的函数。只是触发 Model 里的函数而已,并没有对数据进行操作。

可以类比为一个引路人。

来看一下前台怎么使用 dispatch 的。

const { dispatch } = this.props; //在 dva 中,可以通过 this.props 直接取得 dispatch

dispatch ({
type:‘example/fetch’, //指定哪个 model 层里面的哪个 方法
payload:{name:‘exampleNew’}, //需要传递到 model 层里面的参数。dayload 为固定用法(我自己的理解)。
})
至此,我们就已经在页面上触发了 model 层里面的某个方法,并且把参数一起传递过去了。

type:如果你不需要调用异步的话可以直接 example/save 调用 reducer 下的方法。

7、数据在 Model 中的流向
下面这些文字若有任何不懂的地方请直接参考上面的内容。

如果你上一步是调用 异步(Effects) 里的方法的话

那么你可以 console.log(dayload) 下,看看数据是否有传递过来。

如果需要调用 服务端接口就使用 const data = yield call(接口名,参数名);,然后 console.log(data) 看看数据有没有查询出来。

接着调用 yield put({ type:‘save’,payload:data }) 调用 将参数传递到 reducer 下的方法进行同步。

来到 reducers 的方法下,进行数据操作,操作完成后用 return 将数据返回给 state。

八、稍复杂概念
1、多次调用
在一个 effect 中,可以使用多个 put 来分别调用 reducer 更新状态(state)。

在一个 effect 中,可以存在多个 call 操作。

2、多任务调度
并行。若干任务之间不存在依赖关系,并且后续操作对他们的结果无依赖。
竞争。只有一个完成,就进入下一个环节。
子任务。若干任务,并行执行,全部做完之后,才能进入下一个环节。
并行
const [ result1,result2 ] = yield [
call(service1,param1),
call(service2,param2),
]
竞争
const { result1,result2 } = yield race({
result1:call(service1,param1),
result2:call(service2,param2),
})

好不容易找到的一篇dva教程相关推荐

  1. 3D演示帮你一眼看懂线性规划问题,这篇可视化教程火了

    行早 发自 凹非寺 量子位 | 公众号 QbitAI 你印象中的线性规划是什么样的? 先在二维平面上画图再找最优解? 但毕竟是学理论嘛,大家或多或少都会觉得枯燥晦涩. 那么为何不试试更加直观.好玩的学 ...

  2. mhdd应用详解-入门篇(图文教程)

    mhdd应用详解-入门篇(图文教程) 来源:wxiu.com 作者:fox 时间:2009-03-13 点击: 54 对于专业的 电脑维修人员来说, MHDD是必备的硬盘工具,但是技术人员一般只拿他 ...

  3. 好不容易找到工作,还给期权,要去吗?

    最近,校招已经基本结束了,上周有小伙伴问我这个问题. 首先,我们小伙伴一定要明白校招的作用,校招最大的作用,是能直接进大公司. 错过了校招,想进大公司只能走社招,社招有毕业年限限制,一般是三到五年. ...

  4. 菜鸟的最后一篇php教程

    为什么要起这个名字?其实其中回答了何种人适合看这篇文章--有其他语言基础刚入web后端的初学者.本文主要是对菜鸟教程中的PHP部分做了精简,有基础的能节省不少时间.姊妹篇:菜鸟的最后一篇go教程 PH ...

  5. 扎心!好不容易找到一份工资7500的工作,入职第一天却被告知招错人

    世界之大,真是无奇不有. 近日,广东广州. 25岁吴先生入职第一天,却被HR告知招错人了,然后补偿吴先生50元打车费. 据悉,吴先生的专业是视频剪辑,去公司应聘的岗位也是剪辑岗位. 专业和应聘的岗位相 ...

  6. 没有找到dllregisterserver输入点_Excel教程:框内打的几种输入方法,值得收藏

    51狂欢购 特推超级会员限时疯狂抢购 点击了解 支持微信公众号+小程序+APP+PC网站多平台学习 我们在使用Excel表格时,经常会需要使用打勾的小方框,那么怎样快速的插入呢,今天小编就来带大家一起 ...

  7. [网络篇]ESP8266-SDK教程(三)之TCP通信Server-Client

    纳尼?昨天刚刚打印了个"Hello World!",今天你就让我学习TCP通信?有没有搞错~哈哈,相信很多读者会很迷,其实学习这东西嘛,单单学一些比较简单的,相信没两天就没人看了, ...

  8. python自动化教程_Python自动化开发实战视频课程-全新基础篇_Python教程

    教程名称:Python自动化开发实战视频课程-全新基础篇 课程目录: 0001.51CTO学院-01Pythons10 day1 开课前言- _* N, R+ w/ T 0001.51CTO学院-01 ...

  9. [基础篇]ESP32-RTOS-SDK教程(一)之Windows环境搭建

    当下正是物联网最好的时代,学习新的技术怎么能只学习ESP8266呢?要知道ESP8266还有一个孪生兄弟呢,最重要的是这个孪生兄弟要比ESP8266是更厉害的,所以我们也是非常有必要学习一下的,其实这 ...

最新文章

  1. 单击触发jquery.autocomplete的两种方法
  2. 信号与系统 chapter2 冲激偶函数与阶跃函数
  3. python中until函数_等待应用程序窗口:python中的pywinauto.timings.WaitUntilPasses
  4. 基于jsp+Spring boot+mybatis的图书管理系统设计和实现
  5. Linux快速复制或删除大量小文件
  6. python 最小二乘回归 高斯核_机器学习技法6-(支持向量回归)
  7. leelen可视对讲怎么接线_对讲门铃怎么安装
  8. SPOJ Problem 22:Triangle From Centroid
  9. [Java] 内部类总结
  10. centos 安装mysql5.6.20_Linux学习15-CentOS安装mysql5.6环境
  11. #define中的三个特殊符号:#,##,#@
  12. 三菱je -c中映射表的作用_如何将三菱PLC程序转换成欧姆龙PLC程序?
  13. 什么是黑客?郭盛华告诉你
  14. 消控中心人员配置_消控室的设置要求有哪些?
  15. pytorch 基本数学运算
  16. 高盛报告:未来5-10年区块链将被广泛应用【附下载】
  17. linux trace 进程 文件路径,linux panic 问题定位
  18. 第七十章 SQL函数 $JUSTIFY
  19. 中兴MKT技术岗位介绍
  20. 还不知道transform 3D转换怎么用?看这个就够了

热门文章

  1. 谷粒商城项目学-分布式基础
  2. 【java.lang.ref】FinalReference Finalizer FinalizerThread
  3. 云和恩墨校园招聘开始啦!
  4. 云和恩墨进入基础软件厂商成长象限 未来发展潜力无限
  5. 云和恩墨数据库人才招聘
  6. 敏捷项目管理敏捷工作之冲刺计划
  7. 我为什么鼓励你读计算机领域的博士?
  8. Nginx性能优化(十八)
  9. [业务题]货拉拉数据分析岗简答题, 评估优惠券促销活动的收益效果,评估哪种优惠券对企业更优
  10. 提升电脑运行速度,看这里就够了!