前言
最近写个人博客的时候,想要找一种优雅的方式管理项目中的API请求,于是找到了redux-promise
这样的中间件,之前有在Redux中文文档中学习过中间件,但是并未真正理解,只是简单的学会了applyMiddleware(reducer,thunk)
这样去使用。
借这次机会,认真理解一番redux-thunk
中间件的原理,希望能帮到对redux-thunk
工作原理感兴趣的同学。
本文适合有redux middleware基础的同学阅读。
博主也是个努力成长中的前端小白,这算是第一篇自己的博客(#害羞),还请各位看官佬爷批评指正。
redux-thunk作用
没有中间件的时候,action只能是包含type的普通js对象,redux-thunk就是为了让redux看到,异步Action-Creator可以作为正常的动作创建者的特例而不是完全不同的函数,是redux异步action实现的解决方案之一。
咳咳,有点官方了,简单来说,就是为了能让你dispatch一个函数。
我们知道redux
的中间件是工作在action
发起之后,达到reducer
之前的扩展点(不知道的请先移步至Redux中文文档),因此它更加本质的作用是‘强化’/‘改造’dispatch
函数。这也是它为什么能使dispatch
接收一个函数作为参数的原因。
简单使用
import { createStore, applyMiddleware } from 'redux'
import rootReducer from './rootReducers'
import thunkMiddleWare from 'redux-thunk'
const store = createStore(rootReducer, applyMiddleware(thunk))
理解
在创建store
的时候,我们调用了applyMiddleware(thunk)
,这里其实已经将dispatch
方法强化过了。再通过Provider
组件分发给各个容器组件之后,后续所有使用的store.dispatch
都已经是改造过的dispatch
,为了方便理解,我把核心代码放在一起。
// redux-thunk源码核心
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
// 调用强化之前的dispatch
return next(action);
};
}
const thunk = createThunkMiddleware();
export default thunk;
--------------------------------------------分割线----------------------------------------------
// 理想化的applyMiddleware源码
// 这不是官方的API,只是为了便于理解,可以发现与官方的函数签名不一致
function applyMiddleware(store, middlewares) {
...
let dispatch = store.dispatch
middlewares.forEach(middleware =>
dispatch = middleware(store)(dispatch)
)
return Object.assign({}, store, { dispatch })
}
--------------------------------------------分割线-----------------------------------------------
// 将中间件应用到store中
const storeWithMiddleware = applyMiddleware(store, [thunk])
调用applyMiddleware()
它会遍历一个个中间件,并且调用它两次。thunk
其实就是一个多层嵌套的函数, 通过thunk(store)(dispatch)
调用之后会返回一个函数,并将其赋值给dispatch
,也就是说应用了中间件之后,store.dispatch
变成了类似这个样子:
const dispatch = action => {
// 注意:async function() {} 用typeof判断, 结果也是'function'
if (typeof action === 'function') {
// 调用该函数,并传递参数
return action(dispatch, getState, extraArgument);
}
return next(action);
};
在此之后所有通过dispatch
派发的action
都会经过上述中间件。如果action
是函数,则调用它并传递参数。
在此基础上理解一个action从调用被派发到执行的过程。
当你派发一个异步的action,你会这样写:
UIComponent.js
classes Contact extends React.Component {
render () {
return
...
...
}
handleSend = () => {
this.props.contactAuthor()
}
}
actionCreators.js
export const contactAuthor = (info) => async (dispatch, getState) => {
const result = await postData(`${messageUrl}/contact`, info)
if (result) { dispatch...}
else { dispatch... })
}
}
ContactContainers.js
const mapDispatchToProps = (dispatch) => {
// 简单实现
// return {
// contactAuthor:(info) => {
// 这里dispatch的参数是actionCreator的返回值,异步action函数
// dispatch(contactAuthor(info))
// }
// }
return bindActionCreators({
contactAuthor
}, dispatch)
}
const aboutMeContainers = connect(null, mapDispatchToProps)(Contact)
当点击该按钮后,调用容器组件赋予的contactAuthor()
方法,也就是dispatch(contactAuthor())
, dispatch
的参数是contactAuthor()
的返回值。也就是dispatch
了一个异步函数式的action
,也就是调用了改造后的dispatch
函数,不懂的同学请看注释。
1.将dispatch,getState,args作为action的参数
2.调用action(dispatch, getState, args)
3.异步action运行
结语
这算是我的第一篇博客。。可能写的有点懵,但还是希望有人看到这里能茅塞顿开,对redux-thunk
以及异步中间件的整个运行过程能更好地掌握。
谢谢!