Redux的扩展-中间件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012987546/article/details/80021642

1.什么是中间件?

如果有学习过NodeExpress框架的童孩应该对中间件不陌生。在Express框架中,中间件就是一个函数,这个函数是用来处理请求的过程的,那么在Redux中的中间件也基本类似。Redux的中间件是专门用来处理dispatch分发的action

例如,Redux中间件的使用:

ui-->action-->store-->中间件-->中间件(...)-->reducer-->store--> ui

2.定义函数式的Action

在以前的案例中,我们定义的所有的action都是一个对象类型的action(必须有一个type属性)。 那么下面来介绍一下函数式的action

例如:

/*1.对象类型的action*/
var finish=(str)=>{
    return{
        type:'finish',
        str:str,
    }
}

/*2.函数类型的action*/
var getData=()=>{
    return(dispatch, getState)=>{
        /*分发一个action*/
        dispatch(loading('加载中...'))
        setTimeout(()=>{
            /*过1s后在分发一个action*/
            dispatch(finish('加载完成...'))
        },1000)
    }
}

上面的getData()函数就是一个函数式的action,这个函数直接返回了箭头函数,这个箭头函数会接收到两个参数,一个是:dispatch, 一个是:getState 。这两个参数是谁传递传过来的?是我们下面将要定义的中间件函数createThunkMiddleware()传递过来的。

那这个函数式的action 如何分发?这个时候就要用到Redux的中间件技术

3.中间件技术

1.定义一个中间件

下面定义的中间件的方式可以看做是中间件的模板

中间件的模板定义 , 例如:
({dispatch,getState})=>(next)=>(action)=>{ }

/*
   自定义一个中间件( 这个中间件什么事情都没有做 )
*/
function createThunkMiddleware() {
    return function ({dispatch,getState}) {
        return function (next) {
            return function (action) {
                //....
                return next(action);
            }
        }
    }
}

// or 简写成函数式的编程 

var createThunkMiddleware=()=>{
    return ({dispatch,getState})=>(next)=>(action)=>{
       //...
        return next(action);
    }
}

2.中间件处理函数式的Action

/*自定义一个中间件:专门处理函数类型的action*/
function createThunkMiddleware() {
    return function ({dispatch,getState}) {
        return function (next) {
            return function (action) {
                /**专门处理函数类型的action*/
                if(typeof action === 'function'){
                    /*这里将dispatch,getState两个参数传递给函数式的action*/
                    return action(dispatch,getState);
                }
                return next(action);
            }
        }
    }
}

3.在创建Store时应用中间件

/**ES6的方式导入(注意有些IDE不支持import语法, 也使用ES5的require导入)*/
import {createStore,applyMiddleware} from 'redux';
var initValue={
    str:'',
}
/**
 * 参数一: reducer函数
 * 参数二: 初始化状态树
 * 参数三: 应用中间件
 * @type {Store<S>}
 */
var store =createStore( reducer,initValue,applyMiddleware(createThunkMiddleware()) );

4.完整代码

/*==================action=====================*/
/*1.对象类型的action*/
var loading=(str)=>{
    return{
        type:'loading',
        str:str,
    }
}
/*1.对象类型的action*/
var finish=(str)=>{
    return{
        type:'finish',
        str:str,
    }
}

/*2.函数类型的action*/
var getData=()=>{
    return(dispatch, getState)=>{
        dispatch(loading('加载中...'))
        setTimeout(()=>{
            dispatch(finish('加载完成...'))
        },1000)
    }
}

/*==================reducer=====================*/
var reducer=(state,action)=>{
    var {str,type}=action;
    switch (type){
        case 'loading':
            var s=Object.assign({},state,{str:str});
            console.log(s);
            return s;
        case 'finish':
            var s=Object.assign({},state,{str:str});
            console.log(s);
        default:
            return state;
    }
}
/*==================中间件====================*/

/*自定义一个中间件:专门处理函数类型的action*/
function createThunkMiddleware() {
    return function ({dispatch,getState}) {
        return function (next) {
            return function (action) {
                if(typeof action === 'function'){
                    return action(dispatch,getState);
                }
                return next(action);
            }
        }
    }
}

/*==================store=====================*/
import {createStore,applyMiddleware} from 'redux';
var initValue={
    str:'',
}
/**
 * 参数一: reducer函数
 * 参数二: 初始化状态树
 * 参数三:添加中间件
 * @type {Store<S>}
 */
var store =createStore( reducer,initValue,applyMiddleware(createThunkMiddleware()) );

/*==================简单使用====================*/
console.log('初始化的状态树:',store.getState());
/*1.分发一个 getData() 事件*/
store.dispatch( getData() );

执行后控制台输出:

初始化的状态树: { str: '' }
{ str: '加载中...' }
{ str: '加载完成...' }   // 一秒后才打印

5.查看中间件的调用过程

刚才编写的这个createThunkMiddleware()中间件在 哪里被调用?如何调用?它的参数是如何接收到的? 下面就带着大家查看Redux的源码的实现。

function createThunkMiddleware() {
    /**参数{dispatch,getState}是如何接收到的?*/
    return function ({dispatch,getState}) {
        /** next 是一个函数,是哪个函数? */  
        return function (next) {
            /** 中间件如何接收到用户发出的action */
            return function (action) {
                if(typeof action === 'function'){
                    return action(dispatch,getState);
                }
                return next(action);
            }
        }
    }
}

1.查看applyMiddleware()函数源码

刚才编写的这个createThunkMiddleware()中间件在是在applyMiddleware()这个函数中被使用。所以先看这个函数的实现:

/**
  参数...middlewares :代表可接收一个数组的中间件(我们案例只有一个)
  返回:返回结果是一个函数 (createStore)=> ( , , )=>{ }。
 */
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

applyMiddleware( ) 函数返回结果是一个函数:(createStore)=> ( )=>{ };那么这个函数被谁调用了?参数在哪里传递进来的? 查看: createStore(reducer,initState,middleware) 源码:

export default function createStore(reducer, preloadedState, enhancer) {

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    /**
        applyMiddleware( )函数返回结果是一个函数: 原来在这里被调用了
        例如: enhancer(createStore); 但是这个函数又返回一个函数
        那就再调用:enhancer(createStore)(reducer, preloadedState)
    */
    return enhancer(createStore)(reducer, preloadedState)
  }
}

经过上面enhancer(createStore)(reducer, preloadedState)的函数调用,那么applyMiddleware( )函数返回的函数就被调用了,并且参数也传递过去了。

在回看 applyMiddleware()函数:

/**参数..middlewares: 接收我们编写的中间件*/
export default function applyMiddleware(...middlewares) {
  /** (createStore )=>(reducer, preloadedState, enhancer)*/
  /**上面的参数都是在:enhancer(createStore)(reducer, preloadedState)传递过来的*/
  return (createStore) => (reducer, preloadedState, enhancer) => {
    /**创建store*/
    const store = createStore(reducer, preloadedState, enhancer)
    /**备份dispathc函数(简写:next)*/
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    /**我们的中间件在middleware(middlewareAPI)被传递了参数:{getState,dispatch}*/
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    /**我们的中间件在compose(...chain)里面被调用了*/
    /**compose(...chain)返回的是函数,那就接着调用,并传递参数:store.dispatch*/
    dispatch = compose(...chain)(store.dispatch)
    /**最后再重写了store中的dispatch函数*/
    return {
      ...store,
      dispatch
    }
  }
}

接下来看我们编写的中间件createThunkMiddleware()

function createThunkMiddleware() {
    /**参数{dispatch,getState}是在middleware(middlewareAPI)传递进来的*/
    return function ({dispatch,getState}) {
        /**参数next 是在compose(...chain)(store.dispatch) 传递进来的*/
        /**next 其实就是没有被重写的store.dispatch函数*/
        return function (next) {
        /**最后的这个函数赋值给store中的dispatch函数,参数就是用户分发action的参数*/
            return function (action) {
                if(typeof action === 'function'){
                    return action(dispatch,getState);
                }
                return next(action);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/u012987546/article/details/80021642