dva 如何异步获取接口数据

说在前面

  • 关于redux的框架有很多,这里我用到的是阿里云谦大大的dva(项目地址),这里主要记录下工作中是如何使用dva来异步获取接口数据的。
  • 文末更新至20190619

更新(2019.0619)

  • 最近发现这篇文章虽然写的很烂,但是很多人都能搜到进来瞅两眼,想着再更新一点吧。主要补充一下dva的几个关键词的作用
state的作用
  • State 表示 Model 的状态数据,通常表现为一个 javascript 对象(当然它可以是任何值);操作的时候每次都要当作不可变数据(immutable data)来对待,保证每次都是全新对象,没有引用关系,这样才能保证 State 的独立性,便于测试和追踪变化。
  • 在每一个model中定义state,用于分模块管理全局状态
effects的作用
  • 进行异步操作的地方(ajax…),底层引入了redux-sagas做异步流程控制,由于采用了generator的相关概念,所以将异步转成同步写法
  • 类似于vuex中的Action ,包含异步操作,在vuex中用于提交mutation,从而变更state,在dva中用于提交reducer,用于修改state
Reducer的作用
  • 同步方法,唯一可以修改state的地方,通过effect通过actions传入的值修改state
  • 类似于vuexmutation
Subscription的作用
  • 订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
payload关键字
  • 一般作为参数含义,由UI层通过dispatch一个payload参数在model文件中使用
call
  • 结合yield call发起ajax请求
//getDetailDiscount 接口名
//payload 参数
yield call(getDetailDiscount, payload)
put
  • 使用put关键词提交Reducer
//doDiscounts 一个名字为doDiscounts的同步方法 修改state
yield put({type: 'doDiscounts', payload: response.data});
select
  • effect中可以通过select获取modelstate
  • 定义state
 state:{
     num:1
 }
  • 定义effect
 effect:{
     *getNum({payload},{select}){
         //获取state中的num
         const num = yield select(state => state.num) 
     }
 }
  • model获取state

    other字段为
    model
    namespace

 effect:{
     *getOtherNum({payload},{select}){
         //获取state中的num
         const num = yield select(state => state.other.num) 
     }
 }

这里是正文

第一步、定义model

dva里的model主要是用来开始处理数据和逻辑的。
dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的 subscriptions 。

新建一个一个model/users.js

export default {
  namespace: 'users',
  state: [],
  reducers: {
     doSearch (state, { payload}){
      return {
        ...state,
        searchRsp: payload.data,
      }
    },
  },
  effects:{
  * handleGetSearch({payload, searchRspCallBack}, {call, put}) {
      LogTag('****************************handleGetSearch req*************', payload);
      const response = yield call(getSearch, payload);
      LogTag('****************************handleGetSearch rsp*************', response);
      if (response.status === 200 && response.data.status === 0) {
        searchRspCallBack(response.data.result)
      } else if (response.status === 200 && response.data.status === 1) {
        message.error(response.data.msg)
        yield put({
          type: 'doSearch',
          payload: response.data,
        });
      }
      
  },
  subscriptions :{
      
  }
};

新建ApiService.js文件

import request from '../utils/request';
import {stringify} from 'qs';
/*
* 搜索
* */
export async function getSearch(params) {
  return request(`/search?${stringify(params)}`);
}

这里我主要在effects 定义了一个handleGetSearch方法,
这个方法简单理解:

1、paload是接口的参数,这里打印一下
2、searchRspCallBack是一个回调方法,
  主要是在接口正常调用之后将响应内容在页面层使用
3、yield call(getSearch, payload);是一个异步调用接口参数的方法
4、上述中的if判断主要是说在接口响应到的数据为我与后台正确定义的返回码才进行相应的操作,
比如这里我跟后台约定的是status === 0正常 status === 1 打印后台返回的错误信息
5、searchRspCallBack(response.data.result)
  调用传过来的回调将接口返回数据作为参数传进去
  

reducers方法:用于执行同步操作,改变state等

return {
    ...state,
    searchRsp: payload.data,
    }
改变model中state的searchRsp值为接口返回的响应内容

第二步、使用model中的方法

model中异步获取数据的方法定义好之后如何使用呢?

this.props.dispatch({
      type: 'users/handleGetSearch',
      payload: {
        keywords: this.state.searchText,
        limit: this.state.limit
      },
      searchRspCallBack: this.handleSearchRspCallBack
})

handleSearchRspCallBack = (rsp)=>{
    LogTag(rsp)
}

这是dva中使用dispatch调用model中方法的写法,注意在使用此方法之前要先使用 connect 将model与component连接起来,如果你熟悉 redux,这个 connect 就是 react-redux 的 connect 。

这里使用注解的方法使用connect

@connect(({users, loading}) => ({
  users,
}))

上述dispatch的简单解释:

1、type为要调用的哪个model中的哪个方法,

2、payload为传的参数,这里传了一个keyword与limit数量过去

3、searchRspCallBack: this.handleSearchRspCallBack的意思是将本地的一个方法作为参数传递到model中,
如果model中正确响应之后将响应的内容作为参数传递到这个方法中,
然后我本地写一个handleSearchRspCallBack方法用来接收响应
这样我在component层就可以拿到接口响应的内容了

这是我用来获取接口异步数据的方法第一种,还有一种就是之前在model中执行了reducer同步方法将接口返回的数据保存在了model中的state里面,在componentWillReceiveProps钩子函数也可以拿到我们需要的响应

componentWillReceiveProps(nextProps){
    if(nextProps){
      LogTag(nextProps.users.searchRsp)
    }
  }

上述中nextProps.users.searchRsp就是接口返回的值了

简单的总结

1、先在model中定义一个方法用来执行异步调用接口的方法,可以直接使用回调方法的方法将响应作为参数回调,也可以使用同步reducer的方法将数据保存在state中,后面component层去取model中state的值

2、两种方法都可以获取到异步调用接口返回的响应,第一种好需要定义一个回调方法,第二种获取model中state值需要定义state,在不同的场景使用不同的方法

文章补充:2019.6.1

  • 使用callback非常的不优美,这里官方其实早已提供promise的写法
    *handleUpdateBasicInfo({ payload, user }, { call, put, select }){
      const response = yield call(postUpdateBasicInfo, payload);
      if (response && response.status === 0) {
        return response.data
      }
    },
    //这里在effect中直接return 我们想知道的结果
    
    handleUpdateBasicInfo = (params) => {
    const { dispatch } = this.props;
    dispatch({
      type: 'user/handleUpdateBasicInfo',
      payload: {
        ...params,
      },
    }).then(res=>{
      console.log('res',res)
    })
  };
  //这里then中可以获取到数据

原文首发

    原文作者:w候人兮猗
    原文地址: https://segmentfault.com/a/1190000019622977
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞