dva框架就是基于redux和redux-saga的数据流方案,并内置了react-router和fetch,使得数据管理更加方便,对功能进行了细化,所以使用起来是非常方便的,属于一款轻量级的应用框架.
使用dva框架时,每一个页面主要由三个文件夹下的三个js页面组成
- routes文件夹下的js文件,主要呈现页面需要展示的内容
- models文件夹下的js文件,主要用于控制数据处理的逻辑,同步和异步操作都在这个js文件中完成
- service文件夹下的js文件,只用于调用API获取数据(获取到的数据具体怎么处理是在models文件夹的js文件中进行)
除了以上三个文件以外,访问每一个页面的路径信息在放在src/common/nav.js文件中的.该nav.js文件中主要是引入routes里面的js文件,并给这些引入的文件命名,也就是把这些routes里面的文件作为一个组件并给组件赋予名称方便使用
例如: nav.js
import Login from '../routes/Login';
const components = new Map();
components.set('login', Login);
routes文件夹里面的js文件如何写? 假设有一个Login.js
-
引入需要的工具类js文件;从antd中引入需要使用的组件;从dva中引入connect;从react中引入React,PureComponent
-
@connect( state => ({namespace: state.namespace}) ),其中namespace是models文件夹中的login.js文件的命名空间,必须一一对应
@connect( state => ({propsName: state.namespace}) )// propsName是随便起的属性名,后面可以通过this.props.propsName访问models文件中的信息 -
@Form.create()
-
文件最重要的一个部分,也是最后一个部分
export default class *** extends PureComponent{ state = {};//把需要在state中存储的字段写入并赋初值 componentDidMount(){}//这个函数中写组件挂载后需要执行的操作,通常是获取数据初始化table columns = [ { title: '***', dataIndex: '***',//需要由获取到的数据的哪一个字段对其赋值,如果不需要的话直接为空 key: '***',//识别这个字段的唯一标志,必须有 width: 80,//直接写数字不需要加px等单位 }, ]; renderTable() {//设置表格的样式和属性,比如是否分页,有哪些列,数据源等 //假设这里需要调用models文件夹中login.js文件的add函数,那么使用方法如下: this.props.dispatch({ type: 'namespace/add',//add是models文件夹下login.js文件中的一个函数 payload: {}, callback: () => { //执行add访问数据这个函数成功后需要执行的回调 } }); } renderForm() {}//如何显示表格上方的筛选条件(通常表格上方有一些查询条件和查询按钮) renderModal() {}//如何有弹框的话需要设置弹框如何显示 render(){ const {***} = this.props.propsName;//获取models文件中的属性 /** * this.props有的方法和属性:dispatch,propsName,form,history,location,match */ return ( <Card> {this.renderTable()} {this.renderForm()} {this.renderModal()} </Card> ) } }
models文件夹下的login.js如何书写?
-
引入需要使用的文件,必须引入service文件夹下的login.js中获取数据的几个函数,除非该文件不用获取数据
-
第二个部分也是最后一个部分
export default { namespace: '****',//routes文件夹下的Login.js中写的namespace必须和这里的相同 state : {},//这个state对象中的所有值都是通过this.props.namespace.**获取 effects: {//所有涉及到异步的操作的函数都写在这里,可能会使用到reducers里面的函数 *add({payload, callback}, {call, put}) { yield put({ type: 'changeLoading',//changeLoading是reducers里面的函数名称 payload: true, }); callback && callback();//如果routes文件夹下的Login.js访问models文件夹中的add函数后有回调操作,则执行回调 yield call(**,payload);//***是service中的某个获取数据的函数名 } }, reducers: {//所有同步操作写在这里 changeLoading(state, action) { return { ...state, loading: action.payload } } } }
在service文件夹下,login.js文件有多个获取数据的函数组成,比如它有一个add函数,则
import request from '....';//导入文件,request函数需要自己写,可以通过fetch等多种方式获取数据
export async function add({}) {
//参数需要跟在url路径后面时
return request(`获取数据的路径?param1=${**}¶m2=${**}`, {
method: '**',
body: {}
});
//参数不需要跟在url路径后面时
return request('获取数据的路径', {
method: 'Get',//or 'POST'
body: {}
});
}
以上是我比较习惯的使用方式,还有一种方式,其区别主要在于routes文件夹下的Login.js文件中定义state的方式不同,而models文件夹下的login.js中定义state的方式和上述方法一样.
export default class *** extends PureComponent{
//state: {};替换为以下内容
constructor(props) {
super(props);
this.state = {
...props.namespace
}
}
//访问state中的对象时
this.state = {...this.props.namespace};//如果在componentDidMount()中写了这行代码,后面就可以不用写了
const {**} = this.state;
}