共计 4159 个字符,预计需要花费 11 分钟才能阅读完成。
说在前面
- 关于 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
- 类似于
vuex
中mutation
。
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
获取model
中state
- 定义
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 中可以获取到数据
原文首发
- https://www.ahwgs.cn/ruheshiy…