Ant Design中的dva流程梳理

文章目录

功能

dva流程简单来说就是model层和view层的分离,数据的存储不放在组件的state中,单独拎出来放在model中。项目开发过程中个人感觉全局性数据(比如用户名,用户权限)可以采用这种方法实现。

本例中page层页面List.js负责显示,数据和更新数据的方法放在model层中的DataList.js中。实现效果如下:

在这里插入图片描述

代码

  • page层:src/routes/List.js
import React from 'react';
//dva是1种分层想,将page(routes/List.js)和model(models/ListData.js)进行分层
//其中page只负责页面显示,数据在model中进行处理
import {
    
    connect} from 'dva';


const namespace = 'list';

//说明:第1个回调函数将page层和model层进行连接,返回model中的数据
//并且将返回的数据绑定到this.props中,下面通过this.props.dataList拿数据
//注意不是this.state.dataList
//第2个回调函数,将定义的函数绑定到this.props中,可以调用model层中定义的函数
//通过this.props.add()操作,不是this.state.add()

//*******************以下是第1种写法,直接把2个回调函数写入*******************
//dva的作用是connect model和page
//2个回调函数作为参数
//参数1:将page和model进行连接,返回modle中的数据,并且将返回的数据绑定到this.props
//参数2:将返回的函数绑定到this.props
@connect((state) => {
    
    //state是整个项目全局的state,通过命名空间获取指定的model的state
  return {
    
    //返回1个对象,将返回的值绑定到this.props中
    dataList: state[namespace].data,
    maxNum: state[namespace].maxNum
  }
}, (dispatch) => {
    
    //dispatch的作用:可以调用model层定义的函数
  return {
    
    //将返回的函数,绑定到this.props中
    add() {
    
    
      dispatch({
    
    
        type: 'list/addNewData'  //model的namespace + model中定义的函数名
      });
    },
    init: () => {
    
    //箭头函数写法
      dispatch({
    
    
        type: 'list/initData'
      });
    }
    //下面可以定义多个函数
  }
})
//*******************以上是第1种写法*******************

//*******************以下是第2种写法*******************
// const mapStateToProps = (state) => {
    
    
//   return {//返回1个对象
//     dataList: state[namespace].data,
//     maxNum: state[namespace].maxNum
//   }
// };
//
// const mapDispatchToProps = (dispatch) => {
    
    
//   return {//将返回的函数,绑定到this.props中
//     add() {
    
    
//       dispatch({
    
    
//         type: 'list/addNewData'  //model的namespace + model中定义的函数名
//       });
//     },
//     init() {
    
    
//       dispatch({
    
    
//         type: 'list/initData'
//       });
//     }
//     //下面可以定义多个函数
//   }
// };
//
// @connect(mapStateToProps, mapDispatchToProps)
//*******************以上是第2种写法*******************


class List extends React.Component {
    
    
  //构造函数其实没用,因为props都是从model中获取
  // constructor(props) {
    
    
  //   super(props);
  //
  //   //初始化数据分离到model层
  //   this.state = {
    
    
  //     dataList: [1, 2, 3],
  //     maxNum: 3
  //   }
  // }

  //生命周期函数
  componentDidMount() {
    
    
    //组件加载完成后初始化操作
    this.props.init();
  }

  render() {
    
    
    return (
      <div>
        <ul>
          {
    
    
            this.props.dataList.map((value, index) => {
    
    
              return <li key={
    
    index}>{
    
    value}</li>
            })
          }
        </ul>
        <button onClick={
    
    () => {
    
    
          this.props.add();
        }}>点击
        </button>
      </div>
    )
  }
}

export default List
  • model层:src/models/listData.js
//effects中的request对象
import request from "../utils/request";

export default {
    
    
  namespace: 'list', //src/models中所有的model通过namespace进行区分
  state: {
    
    //state传入下面的addNewData函数
    data: [],
    maxNum: 1
  },

  //新增effects配置,用于异步加载数据
  effects: {
    
    
    //initData在route层页面加载后调用,componentDidMount中调用
    * initData(params, {
    
    call, put}) {
    
    //定义异步方法(*表示异步方法 ),获取到call,put方法
      const url = '/ds/list';  //定义请求的url,具体初始化数据在mock中,注意开始有反斜杠/,和mock对应
      //执行请求,result表示拿到的数据,call中的参数request就是导入的utils/request.js
      let result = yield call(request, url);
      yield put({
    
     //调用reducers中的方法,传递到addNewData里面的result参数
        type: 'addNewData',  //指定方法名,调用reducers中的addNewData
        data: result.data, //传递ajax回来的数据,后面的result是ajax拿到的数据,前面的data是定义的state属性名
        maxNum: result.maxNum
      });
    }
  },

  //model层新增reducer方法,用于更新state中的数据
  reducers: {
    
    
    addNewData(state, result) {
    
    //参数state指的是更新之前的state数据,result代表ajax请求到的数据
      if (result.data) {
    
    //如果state中存在data数据,直接返回,在做初始化的操作
        return result.data;  //返回更新后的数据
      }

      let maxNum = state.maxNum + 1;
      let newArr = [...state.data, maxNum];  //形成新的数组

      //更新状态数据
      return {
    
    //通过return返回更新后的数据,不是setState
        data: newArr,
        maxNum: maxNum
      }
    }
  }
}

  • 路由src/router.js
import React from 'react';
import {
    
    Router, Route, Switch} from 'dva/router';
import List from './routes/List';


function RouterConfig({
    
    history}) {
    
    
  return (
    <Router history={
    
    history}>
      <Switch>
        <Route path="/" exact component={
    
    List}/>
      </Switch>
    </Router>
  );
}

export default RouterConfig;
  • request对象:src/utils/request.js
import fetch from 'dva/fetch';

function parseJSON(response) {
    
    
  return response.json();
}

function checkStatus(response) {
    
    
  if (response.status >= 200 && response.status < 300) {
    
    
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default function request(url, options) {
    
    
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON)
    .then(data => ({
    
     data }))
    .catch(err => ({
    
     err }));
}
  • mock数据:mock/MockListData.js
export default {
    
    
  "GET /ds/list": function (req, res) {
    
    //模拟请求返回数据
    res.json({
    
    
      data: [1, 2, 3, 4],
      maxNum: 4
    });
  }
}
  • 开启mock: .roadhogrc.mock.js
export default {
    
    
  ...require('./mock/MockListData')
};

整体代码:https://github.com/nuptcheng/dva-list-demo.git

猜你喜欢

转载自blog.csdn.net/qq_34307801/article/details/103314708