Redux处理异步Action学习

344 阅读3分钟

常见的处理异步数据包装流程如下

import rootReducer from '../demo/reducers'
![](https://user-gold-cdn.xitu.io/2019/12/3/16ecaaee73d64b9a?w=556&h=180&f=png&s=17948)
import thunkMiddleWare from 'redux-thunk';
import {loggerMiddleWare} from 'redux-logger';
import { createStore, applyMiddleware } from 'redux'

const store = createStore(
    rootReducer,
    applyMiddleware(
        thunkMiddleWare,
        middleWare1,
        middleWare2, 
        ...
        loggerMiddleWare
    )
)

dispatch包装过程解析

  1. applyMiddleware -- 保存和处理中间件 源码如下
export default function applyMiddleware(...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
    }
  }
}

//中间件函数定义模板
const middleWare = ({dispatch, getState}) => next => (action) => {
    //中间件处理逻辑
    console.log(action)

    //中间处理完action后,指向下一个中间件处理
    return next(action)
}

applyMiddleware中,middlewareAPI通过闭包会保存新生成增强的dispatch,依次调用中间件传入middleWareAPI,这样每个中间件生成的函数都能够访问新的dispatch,并且生成的函数依次保存在chain中,通过compose(...chain)(store.dispatch)就会生成新的dispatch

  1. compose(...chain)(store.dispatch)如何增强store.dispatch的
const chain = [f1, f2, f3, ... fn]
//其中函数都是形如以下的函数
fn = next => (action) => {
    //中间件逻辑
    console.log(action)
    //指向下一中间件
    return next(action)
}


/**
 * compose函数
*/
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

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

compose(...chain)处理后生成如下函数

const generateDispatch = (...args) => {
    return f1(f2(f3(f4(...fn(...args)))))
}

当调用f1, f2, f3, ..., fn时,就会生成形如 action => {...}这样的action处理函数,这个action处理函数通过闭包保存了next操作函数

compose(...chain)(store.dispatch)

//相当于执行
generateDispatch(store.dispatch)

这样先调用最后一个fn(store.dispatch),生成一个action处理函数action => {...},这样f1, f2, ... fn-1都会收到后面一个调用返回的action处理函数--这个action函数就是上一个action函数中next函数

比如const actionN = fn-1(action => {...})返回的action处理函数会传参进入fn-2中,成为fn-2返回中的action函数中的next函数。

  1. Redux Thunk Middleware中间件的作用
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

上面已经说了每个action都能够获取到新增强的dispatch以及下一个action处理函数--next函数。

applyMiddleware(
    thunkMiddleWare,
    middleWare1,
    middleWare2, 
    ...
    loggerMiddleWare
)

thunkMiddleWare中间件作为第一个处理中间件,负责通过判定action类型来进行分发

  • 当action是同步数据时,依次调用next函数(中间件生成的action处理函数)处理action,由store.dispatch处理最终的action数据
  • 当action是异步数据,此时action是包含异步过程的函数,调用action(dispatch, getState, extraArgument)处理,然后在异步函数中dispatch获取的action数据,然后重复这个处理过程

Redux middleWare总结出的系统扩展模型

  1. 模型示意图

示意图

  1. 模型说明

原系统

function doSomething(arg) {
  // 系统处理
}

中间件定义形式,其中next指向下一个处理插件

var plugin = next => arg => {
  // 中间件处理逻辑
  pluginDoSomething(arg);
  // 继续下个中间件处理
  return next(arg);
}

构造中间件处理链

function compose(...chain) {
  // 返回一个最终中间件,next将指向原系统api,从而获取扩展的系统
  if (chain.length === 0) {
    return arg => {
      return arg;
    }
  }
  if (chain.length === 1) {
    return chain[0];
  }
  return chain.reduce((a, b) => {
    // 箭头函数无绑定的arguments,只能使用函数声明形式
    return function() {
      return a(b.apply(null, arguments);
    }
  });
}

扩展后的系统 new_doSomething

var chain = [mid1, mid2, mid3, ...];
var new_doSomething = compose(...chain)(doSomething);