UmiJS使⽤dva的⼏种⽅式
dva 是 React 应⽤框架,将React-Router + Redux + Redux-saga三个 React ⼯具库包装在⼀起,简化了 API,让开发 React 应⽤更加⽅便和快捷。dva = React-Router + Redux + Redux-saga
注意使⽤Umijs创建项⽬默认就是ts模式,如果不是ts的可以吧数据类型定义和接⼝约束删除了,吧index.ts改成index.js就可以了
在项⽬加载的时候定义的dva⽂件就被默认加载到dva列表中,也就说项⽬初始化的时候dva就被触发了,
并且dva是全局和vuex⼤致类似下⾯我们来开始dva⽂件类型的创建
1.创建⽂件src/models/index.ts(定义dva)
⽂件夹必须叫models 这是因为UmiJS的约定式的 model 组织⽅式,否者他不去校验这个⽂件⾥的内容是否是dva ,就不会吧dva加⼊dva model 列表中
import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';
export interface IndexModelState {
name: string;
}
export interface IndexModelType {
namespace: 'dva';
state: IndexModelState;
effects: {
query: Effect;
};
reducers: {
save: Reducer<IndexModelState>;
// 启⽤ immer 之后
/
/ save: ImmerReducer<IndexModelState>;
};
subscriptions: { setup: Subscription };
}
const IndexModel: IndexModelType = {
// 命名空间注意这个namespace对应的值必须是唯⼀的不能重复,因为可以定义多个dva所以这⾥必须是唯⼀的做区分
  namespace: 'dva',
// 内部状态
state: {
name: '',
},
// 异步程序
effects: {
*query({ payload }, { call, put }) {
// 正常这⾥发起请求 response最终获得接⼝返回值
// const response = yield call(这⾥是返回Promise对象发起请求, 参数)
yield put({
type: 'save',
payload: {
name: '马丁的车夫'
}
})
},
},
// 同步函数更新数据
reducers: {
save(state, action) {return {
...state,
...action.payload,
};
},
// 启⽤ immer 之后
// save(state, action) {
/
/  state.name = action.payload;
// },
},
// 订阅⼀开始就会被执⾏
subscriptions: {
setup({ dispatch, history }) {
// 监听路由变化根据页⾯地址触发指定的函数(每次切换路由都会被触发)
return history.listen(({ pathname }) => {
if (pathname === '/func') {
// 调⽤ effects 对象⾥的异步函数体
// dispatch({
/
/    type: 'query',
// });
}
});
},
},
};
export default IndexModel;
1.函数组件使⽤
⽅式⼀:
import { connect } from "umi";
import { Button } from 'antd';
const Index = (props: any) => {
console.log(props) // 在props中获取对应的dva中state数据和⽅法
// 不想在subscriptions中去订阅
// 就在这⾥判断⼀下初始化的时候调⽤dva中的effects异步发起请求获取最新数据
if (!props.name) {
}
const handleClick = () => {
}
return (
<div >
获取dva中state的默认数据:{props.name}<br/>
<Button type="primary" onClick={handleClick}>修改</Button>
</div>
)
}
// 获取到最新的state状态并且返回到函数组件中的props中去
const mapState = (state: any) => {
const { name } = state.dva
return {
name: name
}
}
// dva 异步操作
const mapDispatchToProps = (dispatch: (arg0: { type: string; payload?: any }) => void) => ({
onDecrease() {
dispatch({
// 因为dva可以定义多个所以这⾥要采⽤命名的⽅式去区分(⼀般只定义⼀个只作为⼊⼝)
type: 'dva/query', // type:'要调⽤dva中的namespace/要调⽤dva中的effects具体函数名组成的'            payload: { a: 111 }// 传递参数
});
}
})
export default connect(mapState, mapDispatchToProps)(Index)
⽅式⼆:(推荐)
import { connect, useSelector } from "umi";
import { Button } from 'antd';
const Index = (props: any) => {
// 只要调⽤的dva中的state数据更新了这⾥就能触发获取到最新数据
const { name } = useSelector(function (state: any) {
return state.dva
});
const handleClick = () => {
/
/ 调⽤dva中的effects异步
props.dispatch({
type: 'dva/query',
payload: { a: 111 } //传递参数
}).then(()=>{
console.log('异步函数执⾏完毕并且返回结果更新了state')
})
}
return (
<div >
获取dva中state的默认数据:{name}<br />
<Button type="primary" onClick={handleClick}>修改</Button>
</div>
)
}
export default connect(({ dva }: any) => ({ dva }))(Index)
2.类(class)组件使⽤
⽅式⼀:
import React, { Component } from "react";
import { Button } from 'antd';
import { connect } from "umi";
// 对组件的props属性对象⾥的值做约定
interface IpRops {
[x: string]: any
}
class Hello extends React.Component<IpRops> {
handleClick = () => {
console.log(this.props, '触发le')
this.props.dispatch({
type: 'dva/query',
payload: { a: 111 }
}).then(() => {
console.log('更新完毕')
});
}
render() {
return (
<div>
获取dva中state的默认数据:{this.props.name}<br />
<Button type="primary" onClick={this.handleClick}>修改</Button>            </div>
)
}
}
const mapStateUsers = (state: any) => {
return {
name: state.dva.name
}
};
export default connect(mapStateUsers)(Hello);
⽅式⼆:(推荐)
import React, { Component } from "react";
import { Button } from 'antd';
import { connect } from "umi";
// 对组件的props属性对象⾥的值做约定
interface IpRops {
[x: string]: any
}
// this.state做约定
interface StateMode {
[x: string]: any
}
class Hello extends React.Component<IpRops, StateMode> {
constructor(props: any) {
super(props)
this.state = {}
}
componentDidMount() {
}
handleClick = () => {
react router路由传参console.log('点击发起请求')
this.props.dispatch({
type: 'dva/query',
payload: { a: 111 }
}).then(() => {
console.log('更新完毕')
});
}
render() {
const { name } = this.props.dva
return (
<div>
获取dva中state的默认数据:{name}<br />
<Button type="primary" onClick={this.handleClick}>修改</Button>            </div>
)
}
}
export default connect(({ dva }: any) => ({ dva }))(Hello)
优化建议:
定义⼀个dva就可以了,作为⼀个⼊⼝⽂件,吧业务中使⽤到的模块⽤⽂件的⽅式进⾏导⼊⼀个模块定义⼀个⽂件,最终全部导⼊到⼊⼝⽂件中对应的地⽅
我是马丁的车夫,欢迎转发收藏!