react系列--dva框架的使用

769 阅读4分钟

dva框架就是基于redux和redux-saga的数据流方案,并内置了react-router和fetch,使得数据管理更加方便,对功能进行了细化,所以使用起来是非常方便的,属于一款轻量级的应用框架.

使用dva框架时,每一个页面主要由三个文件夹下的三个js页面组成

  1. routes文件夹下的js文件,主要呈现页面需要展示的内容
  2. models文件夹下的js文件,主要用于控制数据处理的逻辑,同步和异步操作都在这个js文件中完成
  3. 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如何书写?

  1. 引入需要使用的文件,必须引入service文件夹下的login.js中获取数据的几个函数,除非该文件不用获取数据

  2. 第二个部分也是最后一个部分

    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=${**}&param2=${**}`, {
         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;
}

如果您觉得写得比较详细对您有帮助,麻烦点个赞,以表鼓励;如果您认为写得不够详细,可以留言告诉我,我再针对性地进行补充