redux 中间件

128 阅读3分钟

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);
            };
        }
    }
}

小结

没有小结