Redux 中间件

176 阅读3分钟

我们简单复习一下 createStore 的调用规则,示例代码如下:

// 引入 redux

import { createStore, applyMiddleware } from 'redux'

......

// 创建 store

const store = createStore(

    reducer,

    initial_state,

    applyMiddleware(middleware1, middleware2, ...)

);

redux 对外暴露了 applyMiddleware 这个方法。applyMiddleware 接受任意个中间件作为入参,而它的返回值将会作为参数传入 createStore,这就是中间件的引入过程

中间件可以给我们增强createStore的能力,比如异步 我们可以看看我们常见的异步Action解决方案

在针对 Redux 源码主流程的分析中,我们不难看出这样一个规律——Redux 源码中只有同步操作,也就是说当我们 dispatch action 时,state 会被立即更新。

那如果想要在 Redux 中引入异步数据流,该怎么办呢?Redux 官方给出的建议是使用中间件来增强 createStore。支持异步数据流的 Redux 中间件有很多,其中最适合用来快速上手的应该就是 redux-thunk了。

// 引入 redux-thunk

import thunkMiddleware from 'redux-thunk'

import reducer from './reducers'

// 将中间件用 applyMiddleware 包装后传入

const store = createStore(reducer, applyMiddleware(thunkMiddleware))

redux-thunk 带来的改变非常好理解,它允许我们以函数的形式派发一个 action

// axios 是一个用于发起异步请求的库

import axios from 'axios' 

// 引入 createStore 和 applyMiddleware

import { createStore, applyMiddleware } from 'redux';

// 引入 redux-thunk

import thunk from 'redux-thunk';

// 引入 reducer

import reducer from './reducers';

// 创建一个有 thunk 中间件加持的 store 对象

const store = createStore(

  reducer,

  applyMiddleware(thunk)

);

// 用于发起付款请求,并处理请求结果。由于涉及资金,我们希望感知请求的发送和响应的返回

// 入参是付款相关的信息(包括用户账密、金额等)

// 注意 payMoney 的返回值仍然是一个函数

const payMoney = (payInfo) => (dispatch) => {

  // 付款前发出准备信号

  dispatch({ type: 'payStart' })

  fetch().then(res => { dispatch()})

  return axios.post('/api/payMoney', {

    payInfo

  })

  .then(function (response) {

    console.log(response);

    // 付款成功信号

    dispatch({ type: 'paySuccess' })

  })

  .catch(function (error) {

    console.log(error);

    // 付款失败信号

    dispatch({ type: 'payError' })

  });

}

// 支付信息,入参

const payInfo = {

  userName: xxx,

  password: xxx,

  count: xxx,

  ......

}

// dispatch 一个 action,注意这个 action 是一个函数

store.dispatch(payMoney(payInfo));

这里有两点需要注意的:

  1. 首先, dispatch 的入参从 action 对象变成了一个函数
  2. 其次,Redux 中间件将会在 action 被分发之后、到达 reducer 之前执行

Redux中间件执行时机

如果有多个中间件 多个Redux中间件执行

对于 Redux 中间件的工作模式,需要牢牢把握以下两点:

  1. 中间件的执行时机,即 action 被分发之后、reducer 触发之前;
  2. 中间件的执行前提,即 applyMiddleware 将会对 dispatch 函数进行改写,使得 dispatch 在触发 reducer 之前,会首先执行对 Redux 中间件的链式调用。

compose - 函数的合成 书写中间件 applyMiddleWare(thunk1, thunk2, thunk3, thunk4); 如何实现链式顺序调用? 这里就有一个compose方法,不考虑逻辑,核心的实现代码为

funcs.reduce((a, b) => (...args) => a(b(...args)))

这里巧妙的使用了array的reduce方法,关于reduce方法,可以参考 array.reduce

这里给出一个示例

const funcs = [f1,f2,f3,f4]
funcs.reduce((a, b) => (...args) => a(b(...args)))
callbackabcurrentIndexreturn value
firstCallf1f21(...args) =>f1(f2(...args))
secondCall(...args) =>f1(f2(...args))f32(...args) =>f1(f2(f3(...args))
thirdCall(...args) =>f1(f2(f3(...args))f43(...args) =>f1(f2(f3(f4(...args))

通过这种方式,可以将我们传入的多个thunk中间件,进行链式的执行。