redux-thunk 是一个比较流行的 redux 异步 action 中间件,比如 action 中有 setTimeout 或者通过 axios 通用远程 API 这些场景,那么就应该使用 redux-thunk 了。redux-thunk 统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。换言之,中间件都是对store.dispatch()的增强
安装redux-thunk依赖
npm install redux-thunk
cnpm i redux-thunk
yarn add redux-thunk
引入redux-thunk
import thunk from 'redux-thunk'
配置redux-thunk和redux-devtools一起使用
import { createStore, applyMiddleware, compose } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'
const composeEnhancers =
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunk),
);
const store = createStore(
reducer,
enhancer
)
export default store
applyMiddleware是redux的一个原生方法,将中间件放入一个数组,以此执行。扩展(redux-middleware)[https://redux.js.org/advanced/middleware]
使用thunk的ajax请求
配置好了redux-thunk就可以将 componentDidMount里的异步请求移除,没有用redux-thunk之前,actionCreators.js 中export的都是一个action对象。用了redux-thunk之后可以返回一个函数了, 可以返回一个异步请求
// actionCreators.js
export const getTodoList = () => {
return (dispatch) => {
axios.get('http://localhost:8000/list').then((res) => {
const listData = res.data.data.list
const action = initListAction(listData)
dispatch(action)
})
}
}
// Todolist.js
import {
getTodoList
} from './store/actionCreator'
componentDidMount() {
this.props.handleInitList()
}
const mapDispatchToProps = (dispatch) => {
return {
handleInitList() {
const action = getTodoList()
dispatch(action)
}
}
}
redux-thunk的工作流程(原理)
一般情况下store接受的action都是action对象,使用了redux-thunk
后,store可以接收函数的action,接收到并且直接执行,这样就发出了一个异步请求。请求返回结果后,需要将数据告知store,进行数据更新,此时可以再发送一个action,来更新store数据。
export const initListAction = (data) => (
{
type: INIT_LIST_ACTION,
data
}
)
export const getTodoList = () => {
// store 在执行函数的时候,会传一个dispatch
return (dispatch) => {
axios.get('http://localhost:8000/list').then((res) => {
const listData = res.data.data.list
// 拿到数据后 通过dispatch一个action, 告知store数据更新了
const action = initListAction(listData)
dispatch(action)
})
}
}
异步主要用 middleware,thunk 只是一个可以让你在一个 dispatch 中能够继续 dispatch 的中间件。后续会有redux-sage的介绍。
redux-thunk的源码解析
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
// 这里判断action是否是function, 若是就改写dispatch, 直接执行该函数,并且将dispath、getState传给该函数
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
如果传入的参数是函数,则执行函数。否则还是跟之前一样dispatch(PlainObject).
为什么要使用redux-thunk
为什么最好不要把异步请求放到生命周期里,是因为随着业务量的增大,会有越来越多的异步请求,生命周期会异常庞大。建议还是把异步请求放到一个actionCreators里去管理。
将异步请求放到actionCreators里去管理,比放到生命周期里, 更好的做自动化测试,具体是怎么好做的呢?后续更新!