redux 中的reducer 是一个纯函数,对于一样的输入需要是一样的输出,所以对于一些副作用函数,不能再reducer 中进行。那么就需要中间件函数。通常来说,我们是 组件 dispatch(action) =》 reducer =》 store ,我们借助中间件,可以在dispatch(action )之前,修改action 内容,然后再进入reducer 中处理。
applyMiddleware
这是在redux 中引入中间件需要使用的方法,他会返回一个新的store,并且这个store中的dispatch 方法,
是已经经过中间件修改后的方法,不仅能发送action 甚至能发送函数
例如,我们使用redux-thunk 与redux-logger 中间件
const store = createStore(reducer,applyMiddleware(thunk(),logger()));
通过这样,我们进引入了 redux-thunk, 与 redux-logger 中间件。
我们先看一下,applyMiddleware 是怎么引入中间件的。
// applyMiddleware source code
export default function applyMiddleware(...middlewares) {
// middlewares 是所有的中间件函数。
return (createStore) => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
现在逐行解释一下,applyMiddler 返回了一个高阶函数
return (createStore) => (...args) => {
const store = createStore(...args)
}
看到这个,还得刷到createStore 中,最开头的几个判断
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error(
`Expected the enhancer to be a function. Instead, received: '${kindOf(
enhancer
)}'`
)
}
return enhancer(createStore)(reducer, preloadedState)
}
这段中的enhancer 函数 就是 applyMiddleware(thunk(),logger()) 返回的函数。
我们看到,他又调用了 enhancer(createStore)(reducer, preloadedState),其实就相当于
在applyMiddleware 中创建store。
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
这里暂时将dispatch 设置暂时不能调用,调用只会抛出一个错误。
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
这一段是让 middleware 能正常使用 store的功能 如 getState 与 dispatch。
dispatch = compose(...chain)(store.dispatch)
这里是将 dispatch 方法,被所有中间件加工,生成一个新的dispatch。
return {
...store,
dispatch,
}
最后再将加工好的dispatch 返回出去。
redux-thunk
以redux-thunk 为例,当我们使用这个中间件后,我们可以在dispatch 中调用函数。
// 例如
const login = (username) => (dispatch) => {
post({username}).then((res) => {
dispatch({type: 'login'})
}).catch((err) => {
throw new Error('err => ',err)
})
}
dispatch(login('username'))
上面例子是使用redux-thunk 后对于login的一个处理函数,当我们登陆成功后,
会dispatch 登陆成功的action 失败则抛出错误。
thunk 源码
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
说点人话
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => {
// 这一步是用stroe 中的dispatch 与 getState 使中间件能操作store 的方法
return next => {
// 这里是使用compose 对dispatch 进行改造,
// next 表示使用下一个中间件来操作action ,
// 当前中间件对action 已经操作完,或者无需操作
return action => {
// 这里就是用改造后的dispatch 来派发action
if (typeof action === 'function') {
// 如果action 是函数,则调用,并且传入dispatch ,getState 等方法
return action(dispatch, getState, extraArgument);
}
// 如果不是函数,则当前中间件不用处理,调用下一个中间件来处理
return next(action);
};
}
}
}
小结
没有小结