乐趣区

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 字段为 modelnamespace

 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 中可以获取到数据

原文首发

  • https://www.ahwgs.cn/ruheshiy…
退出移动版