当前位置:网站首页>Dva.js 新手入门指南
Dva.js 新手入门指南
2022-08-03 10:56:00 【InfoQ】
- 一、介绍
- 二、环境搭建和使用
- 三、全局架构
- 四、Model 包下文件架构
- 五、connect 连接 Model 和 Route 页面下的数据
- 六、初始化数据 和 Model 数据比对
- 七、数据显示和操作的流程
- 八、稍复杂概念
一、介绍
1、什么是 Dva
2、Dva 解决的问题
- 文件切换问题。redux 的项目通常要分 reducer, action, saga, component 等等,他们的分目录存放造成的文件切换成本较大。
- 不便于组织业务模型 (或者叫 domain model) 。比如我们写了一个 userlist 之后,要写一个 productlist,需要复制很多文件。
- saga 创建麻烦,每监听一个 action 都需要走 fork -> watcher -> worker 的流程
- entry 创建麻烦。可以看下这个redux entry的例子,除了 redux store 的创建,中间件的配置,路由的初始化,Provider 的 store 的绑定,saga 的初始化,还要处理 reducer, component, saga 的 HMR 。这就是真实的项目应用 redux 的例子,看起来比较复杂。
3、Dva 的优势
- 易学易用,仅有 6 个 api,对 redux 用户尤其友好,配合 umi 使用后更是降低为 0 API
- elm 概念,通过 reducers, effects 和 subscriptions 组织 model
- 插件机制,比如dva-loading可以自动处理 loading 状态,不用一遍遍地写 showLoading 和 hideLoading
- 支持 HMR,基于babel-plugin-dva-hmr实现 components、routes 和 models 的 HMR
4、Dva 的劣势
- 未来不确定性高。[email protected] 前年提出计划后,官方几乎不再维护。

二、环境搭建和使用
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" }]
+ ]
}
.
├── 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');
(1)、创建 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
(4)、配置路由
index.js
router.js
(5)、启动应用
2、router.js
router.js
import IndexPage from './routes/IndexPage';
import HomePage from './routes/HomePage';
<Router history={history}>
<Switch>
<Route path="/" exact component={IndexPage} />
.
.
.
<Route path="/home" exact component={HomePage} />
</Switch>
</Router>
使用
path
component
home
解释一下
history
location
location
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
namespace
js
home.js
namespace
home
2、state
this.props
3、reducers
action
reducers
state
example.js
reducers
reducers: {
save1(state, action) {
return { ...state, ...action.payload };
},
save2(state, action) {
return { ...state, ...action.payload };
},
},
(1)、save
save
(2)、state
state
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
state
state
state
...state
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
reducers
payload
reducers
(6)、select
select
select
const homeName = yield select(state => state.home);
home
state
(5)、subscription
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
import { connect } from 'dva';
class ~ extends React.Components
connect
export default connect(({index}) => ({index}))(IndexPage);
index
index
namespace
六、初始化数据 和 Model 数据比对
1、初始化数据
index.js
initialState
model
namespace
2、Model -> state
initialState
model
state
{}
initialState
七、数据显示和操作的流程
1、编写 Route 页面
class
class ~ extends React.Component{}
import React from 'react';
const Example = ({dispatch,全局 `index.js` 里你需要的参数对象名称}) => {
return (<div></div>)
}
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';
<Route path="/example" exact component={Example} />
5、使用 connect 连接
Route
example.js
connect
import { connect } from 'dva';
export default connect(({ example }) => ({ example }))(Example);
this.props
example
6、前台调用 Model 层方法
dispatch
dispatch
action
Model
dispatch
const { dispatch } = this.props; //在 dva 中,可以通过 `this.props` 直接取得 `dispatch`
dispatch ({
type:'example/fetch', //指定哪个 model 层里面的哪个 方法
payload:{name:'exampleNew'}, //需要传递到 model 层里面的参数。dayload 为固定用法(我自己的理解)。
})
type
example/save
reducer
7、数据在 Model 中的流向
console.log(dayload)
const data = yield call(接口名,参数名)
;
console.log(data)
yield put({ type:'save',payload:data })
reducer
reducers
return
state
八、稍复杂概念
1、多次调用
effect
put
reducer
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),
})
子任务
多次调用
边栏推荐
- numpy
- MATLAB程序设计与应用 2.7 结构数据与单元数据
- 聊天app开发——防炸麦以及节省成本的内容鉴定方法
- Mysql OCP 75 questions
- Babbitt | Metaverse daily must-read: Players leave, platforms are shut down, and the digital collection market is gradually cooling down. Where is the future of the industry?...
- 【JDBC以及内部类的讲解】
- BPMN和DMN基本概念和使用案例
- 苏州大学:从PostgreSQL到TDengine
- Machine Learning (Chapter 1) - Feature Engineering
- 通过GBase 8c Platform安装数据库集群时报错
猜你喜欢
深度学习经典网络 -- Inception系列(稀疏结构)
苏州大学:从PostgreSQL到TDengine
完全背包问题
VL53L0X V2 laser ranging sensor collects distance data serial output
机器学习(第一章)—— 特征工程
巴比特 | 元宇宙每日必读:玩家离场,平台关停,数字藏品市场正逐渐降温,行业的未来究竟在哪里?...
干货!一种被称为Deformable Butterfly(DeBut)的高度结构化且稀疏的线性变换
[Star Project] Little Hat Plane Battle (9)
Summary of redis basics - data types (strings, lists, sets, hashes, sets)
How to use outside the PHP command in the container
随机推荐
苏州大学:从PostgreSQL到TDengine
【TypeScript】为什么要选择 TypeScript?
error C2872: “flann”: 不明确的符号 解决方法
ScrollView嵌套RecyclerView滚动冲突
Advanced use of MySQL database
SAP 电商云 Spartacus UI 的 External Routes 设计明细
servlet生命周期详解--【结合源码】
Matplotlib
请问应该用什么关键字将内容主题设置为 dark 呢
Question G: Word Analysis ← Questions for the second provincial competition of the 11th Blue Bridge Cup Competition
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
GBase 8c与openGauss是什么关系?
全新的Uber App设计
如何通过DBeaver 连接 TDengine?
509. 斐波那契数
微信多开批处理(自动获取安装路径)
面试突击71:GET 和 POST 有什么区别?
浪潮—英伟达打造元宇宙新方案,虚拟人的故事将再破你的认知
优炫数据库在linux平台下服务启动失败的原因
深度学习100例——卷积神经网络(CNN)实现服装图像分类