1.配置,在config.js中开启配置
dva: {
immer: true, // 表示是否启用 immer 以方便修改 reducer
hmr: true, // 表示是否启用 dva model 的热更新
},
2.约定式的 model 组织方式
符合以下规则的文件会被认为是 model 文件,
·src/models 下的文件
·src/pages 下,子目录中 models 目录下的文件
·src/pages 下,所有 model.ts文件(不区分任何字母大小写)
比如:
+ src
+ models/a.ts
+ pages
+ home/models/index.js
+ mine/model.js
ps:根据约定,umi会默认把models文件下的index.js 作为dva,所以一般在一个模块或者路由下建一个models文件
3.如何使用?
比如我们在home模块下,新建modules/index.ts(这里使用了typescript),在index.ts中写入
import type { Reducer, Effect, Subscription } from 'umi'
import request from 'umi-request'
import { getSchool } from '@/api/api'
/**
* @description 声明HomeModelState中state的数据类型
*/
export interface HomeModelState {
name: string
age: number
}
/**
* @description 声明HomeModelType的数据类型
*/
export interface HomeModelType {
namespace: 'home'
state: HomeModelState
reducers: { setName: Reducer<HomeModelState> }
effects: { query: Effect }
subscriptions: { setup: Subscription }
}
/**
* @description 定义HomeModel
*/
const HomeModel: HomeModelType = {
/**
* @param namespace: 如果没有声明 namespace,会以文件名作为 namespace
*/
namespace: 'home',
state: {
name: 'test',
age: 12,
},
/**
* @description // reducers 用来处理同步操作,与Vuex 中mutions 中一样
* @param state: HomeModelType的state对象
* @param action:调用该方法传过来的值
* @param setName:这里的名字根据实际用途命名,可以在reducers中无限添加函数
*/
reducers: {
setName(state: any, action: any) {
state.name = action.payload
return state
},
},
/**
* @description effects 用来处理异步操作,与Vuex 中actions 中一样,调用方法与reducers一样,这点与Vux不同
* @param payload:调用query时传过来的参数,比如这里放的是http请求,需要在路由中传参数进来
* @param put
*/
effects: {
*query({ payload }, { call, put }) {
/**
* @description 不使用call res与res1的写法一致 ,一般使用res的写法
*
*/
// 方式1
const res = yield getSchool({ name: payload })
// const res1 = yield request.post('/api/getNames', { data: { name: payload } })
if (res.success) {
yield put({
type: 'setName',
payload: {
data: res.data,
},
})
}
/**
* @description 使用call result与result1的写法一致 ,一般使用result的写法
*
*/
const result = yield call(getSchool, { data: { name: payload } })
// const result1 = yield call(request.post, '/api/getNames',{data: {name: payload}})
if (result.success) {
yield put({
type: 'setName',
payload: {
data: result.data,
},
})
}
},
},
/**
* @description 定义在subscriptions的方法 只要符合条件的 全局触发,比如setup中的监听window的窗口变化,只要
* 浏览器的窗口发生了变化,在任意一个路由中都能监听并触发
*/
subscriptions: {
setup({ dispatch }) {
window.onresize = () => {
dispatch({ type: 'setName', payload: Math.random() })
}
},
},
}
export default HomeModel
4.如何调用dva封装的方法?
假设我们想在home/index.ts中调用
// 使用umi中的connect方法与路由进行连接,使用props 与dva中model中的state数据进行绑定
import { connect } from 'umi'
const namespace: string = 'home'
const Home = (props: any) => {
const { name } = props
const query = () => {
props.query('test1')
}
return <div onClick={query}>{name}</div>
}
function masterProps(state: any) {
const { name } = state[namespace]
return {
name
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
setName(payload: string) {
const action = {
type: `${namespace}/setName`,
payload: payload
}
dispatch(action)
},
query(payload: string) {
const action = {
type: `${namespace}/query`,
payload: payload
}
dispatch(action)
}
}
}
export default connect(masterProps, mapDispatchToProps)(Home)