dva开发参考资料
https://blog.csdn.net/TurkeyCock/article/details/88427158
https://www.yuque.com/flying.ni/the-tower/tvzasn#d6fa1d0c
[https://github.com/gege-circle/home/issues/783
](https://github.com/gege-circle/home/issues/783)
搞懂 DvaJS 原理
[https://github.com/gege-circle/home/issues/783
](https://github.com/gege-circle/home/issues/783)
https://github.com/dvajs/dva-knowledgemap
dva是什么
一个基于 redux,redux-saga, react-router,react-router封装的的数据流方案
- 内置了 ,和fetch,expres的 mock方案
- 最新的是 react-router-dom代替 react-router
- dva特性:就是把一个路由下的state、reducer、sagas 写到一块了,清晰明了
dva将所有与数据操作相关的逻辑集中放在一个地方处理和维护,让代码更加清晰可控
设计model时将不同类型的业务需求数据操作分开处理,便于维护
redux的缺点
- 不够扁平化
- 页面配套(action、reducer)过于繁琐、复杂
dva概念
6个 API,redux用户可以快速上手
- reducers
- effects
- models
- subscriptions
5个API
const app = new dva({options});
app.use() // Hooks plugin
app.models() // ModelObject
app.router() // Function
app.start() // HTMLElement
8个概念
- State 整个应用的数据层,初始state在model中定义,由model state组成全局state
- namespace,model state在全局state中所用到的key
- action
- model
- reducers
- effects
- subscription
- router
- RouteComponent 业务组件
dva特点
支持,HMR,模块热替换
基于 babel-plugin-dva-hmr(https://github.com/dvajs/babel-plugin-dva-hmr)
实现 components、routes 和 models的 HMR
dva插件机制
dva-loading,自动处理 loading的 true & false,不用一遍遍地写 showLoading 和hideLoading
dva数据流向
改变数据通过 dispatch一个 action
- 同步,直接通过 reducers 改变 state
异步,先触发 effects 然后, effects里面 put(action) 流向 reducers 最终改变 State
const action = { type: 'init', payload: {} }
dispatch(action);
如果:dispatch的type,在 reducers和 effects都有,会同时触发
先触发 reducers
后触发 effects,
export default {
namespace: 'list',
state: {},
reduers: {
init() {},
},
efffects: {
*init() {}
},
subscriptions: {
setup({ dispatch, history}){
}
},
}
业务建模思维:单向数据流动过程
- 从设计model state开始进行抽象数据
- 完成component后,将组件和model建立关联
- 通过dispatch(action),在reducer中更新数据完成数据同步处理
- 通过 effects数据异步处理,然后调用 reducer更新全局state
dva将所有与数据操作相关的逻辑集中放在一个地方处理和维护,让代码更加清晰可控
设计model时将不同类型的业务需求数据操作分开处理,便于维护
redux workflow
分层思维
为了让数据流更易于维护,redux分成了store,reducer,action等模块,各司其职,软件开发也是一样
- routes
- models
- service
routes
routes里面存放页面组件,负责和用户直接打交道
- 渲染页面
- 接受用户的操作和输入,事件交互
路由决定进入url渲染哪些Component
routes也就是日常开发的核心,代码编写都在这个目录里面
routes/index.js hooks组件
import React, { useEffect } from 'react';
import { connect } from 'dva';
function App({dataSource, loading, dispatch}) {
useEffect(() => {}, [
dispatch({type: 'list/init', payload: {page: 1, limit: 10}});
]);
return (
<div>
</div>
)
}
function mapStateToProps(state) {
return {
dataSource: state.list.dataSource,
loading: loading.effects['list/init'],
}
}
export default connect(mapStateToProps, null)(App);
- 需要 connect Model的组件都是 RouteComponents
- /components/目录下则是纯组件,尽量不要 connect链接 models,通过 props传递数据
models
负责处理数据,处理页面业务逻辑,负责页面的数据状态
- 数据清晰,
- ajax的异步逻辑判断
每个路由都对应一个model,
这个model掌管这个路由的所有状态(action、state、reducer、sagas),
组件想改变状态dispatch({type, action}) type名字就行了
models相关概念
- namespace,一个大型应用可能包含多个 model,通过 namespace 区分
- state
- 只能有 reducers修改 state
- dispatch(action)
- reducers,修改 state
- reducer 是一个纯函数,接受当前的state 及一个 action对象,返回新的 state
- action 对象里面可以包含数据体(payload)作为入参,需要返回一个新的 state
- reducer 是唯一可以更新 state
- effects
- 处理异步操作,和API接口的业务逻辑
- 不可以修改 state,要通过触发 action 调用 reducer 实现对 state 的操作
- subscriptions 订阅
models模板
export default {
namespace: 'count',
state: {
},
reducers: {
add(state, action) {
},
},
effects: {
*asyncAdd(action, effect) {
const { call, put } = effect;
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
}
action格式
{ type: 'add', payload: todo }
services
http的 API接口对象,进行纯粹的接口管理