Redux的Action本身只一个如下形式的对象:
{
type: ADD_TODO,
payload: 'Other args'
}
但是官方推荐我们使用一个ActionCreator的方法来返回一个action
export function addTodo(arg) {
return {
type: ADD_TODO,
payload: arg
}
}
这样做有两个好处
1. 可以在actionCreator中传入参数来返回动态的action。
2. 可以让actionCreator不再返回一个对象,而是返回一个方法,此时actionCreator成了一个thunk,
也就是一个延迟执行值的方法,如果想知道thunk执行的结果,需要在合适的时候调用thunk()方法,如下面的例子。
export function addTodo(arg) {
return function (dispatch) {
return fetch(`http://www.xxx.com/a.json`)
.then(
response => response.json()
)
.then(json =>
dispatch(receiveData(json))
)
}
}
上面的例子就创建了一个异步的action,actionCreator模糊了同步action和异步action的差异,你只需要调用方法即可,不用关心actionCreator返回的action类型。
现在的问题是Redux默认是只支持同步Action,也就是actionCreator应当返回一个对象,现在我们的Creator返回了一个方法,Redux并不会知道如何处理,所以这个时候我们就需要MiddleWare了。
MiddleWare的本质是重写dispatch方法,比如官网示例的以下方法即可让所有的dispatch都具有日志功能。
let next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
即使知道要重写dispatch方法,我们仍需要了解Redux的applyMiddleWare是如何处理middleware才能写一个中间件,这里摘一段applyMiddleWare的源码:
import compose from './compose'; export default function applyMiddleware(...middlewares) { return (next) => (reducer, initalState) => { let store = next(reducer, initalState); let dispatch = store.dispatch; let chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map( middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch }; } }
通过代码可以知道middleware是一个方法,会被注入一个对象({getState, dispatch})执行,返回的chain中的元素仍然是一个方法,被聚合后注入store.dispatch再次调用,最终会得到一个新的、受到了污染的disptach,这个新的disptach应该有如下关系:
newDispatch = middleware ({getState, dispatch})(nextDispatch)
之所有第二个参数叫nextDispatch,是因为compose函数处理时,每经过一个chain都是返回一个基于下一个dispatch包装的新dispatch(chain中最后的方法最先执行),如果我们要写一个中间件,也就是重写dispatch方法,那么middleware的签名应该是这样:
middleware = ({getState, dispatch}) => nextDispatch => action => {}
那么thunk中间件如下:
thunk = ({getState, dispatch}) => nextDispatch => action =>{
if(typeof action === 'function') {
return action(dispatch)
}
return nextDispatch(action)
}
那么一个异步action实际就是一个方法,中间件会调用这个方法,同时会传一个dispatch给这个方法,rudux不关心这个方法要做什么,只要方法里面再调用dispatch方法即可让rudux更新状态.