美文网首页
redux中间件的理解

redux中间件的理解

作者: any_5637 | 来源:发表于2020-04-20 20:16 被阅读0次

    我们知道redux的基本用法是:用户发出Action,Reducer计算出新的state,view重新渲染。像这样立即算出state的是同步的操作;
    异步的操作是怎么的呢?
    我们可以使用中间件进行处理:使得Reducer在异步操作结束后自动执行。
    我们都知道,在redux中:
    1 ) Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
    2 ) View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。
    3 ) Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
    Redux 的中间件提供的是位于 action 被发起之后,到达 reducer 之前的扩展点,换而言之,原本 view -> action -> reducer -> store 的数据流加上中间件后变成了 view -> action -> middleware -> reducer -> store ,在这一环节我们可以做一些 “副作用” 的操作,如 异步请求、打印日志等。
    以日志输出 Logger 为例:

    import { createStore, applyMiddleware } from 'redux'
    /** 定义初始 state**/
    const initState = {
      score : 0.5
    }
    /** 定义 reducer**/
    const reducer = (state, action) => {
      switch (action.type) {
        case 'CHANGE_SCORE':
          return { ...state, score:action.score }
        default:
          break
      }
    }
    
    /** 定义中间件 **/
    const logger = ({ getState, dispatch }) => next => action => {
      console.log('【logger】即将执行:', action)
    
        // 调用 middleware 链中下一个 middleware 的 dispatch。
      let returnValue = next(action)
    
      console.log('【logger】执行完成后 state:', getState())
      return returnValue
    }
    
    /** 创建 store**/
    let store = createStore(reducer, initState, applyMiddleware(logger))
    
    /** 现在尝试发送一个 action**/
    store.dispatch({
      type: 'CHANGE_SCORE',
      score: 0.8
    })
    /** 打印:**/
    // 【logger】即将执行: { type: 'CHANGE_SCORE', score: 0.8 }
    // 【logger】执行完成后 state: { score: 0.8 }
    
    

    要理解上面这段代码,首先要从创建store的createStore函数说起:createStore函数接收参数为(reducer, [preloadedState], enhancer),其中preloadedState为初始state,那么 enhancer 又是什么呢?从官方文档可以看到,StoreCreator 的函数签名为

      type StoreCreator = (reducer: Reducer, initialState: ?State) => Store
    

    是一个普通的创建 store 的函数,而 enhancer 的签名为

    type enhancer = (next: StoreCreator) => StoreCreator
    

    可知enhancer是一个组合 StoreCreator 的高阶函数, 返回的是一个新的强化过的 StoreCreator,再执行StoreCreator就能得到一个加强版的 store。在本例里形参enhancer即为applyMiddleware,从下面的源码可知,applyMiddleware 改写了 store 的 dispatch 方法,新的 dispatch 即是被所传入的中间件包装过的。

    export default function applyMiddleware(...middlewares) {
      return (createStore) => (reducer, preloadedState, enhancer) => {
        // 接收 createStore 参数
        var store = createStore(reducer, preloadedState, enhancer)
        var dispatch = store.dispatch
        var chain = []
    
        // 传递给中间件的参数
        var middlewareAPI = {
          getState: store.getState,
          dispatch: (action) => dispatch(action)
        }
    
        // 注册中间件调用链,并由此可知,所有的中间件最外层函数接收的参数都是{getState,dispatch}
        chain = middlewares.map(middleware => middleware(middlewareAPI))
        //compose 函数起到代码组合的作用:compose(f, g, h)(...args) 效果等同于 f(g(h(...args))),具体实现可参见附录。从此也可见:所有的中间件最二层函数接收的参数为 dispatch,一般我们在定义中间件时这个形参不叫 dispatch 而叫 next,是由于此时的 dispatch 不一定是原始 store.dispatch,有可能是被包装过的新的 dispatch。
        dispatch = compose(...chain)(store.dispatch)
    
        // 返回经 middlewares 增强后的 createStore
        return {
          ...store,
          dispatch
        }
      }
    }
    
    

    这样下来,原来执行 dispatch(action) 的地方变成了执行新函数

    (action)=>{
        console.log('【logger】即将执行:', action)
        dispatch(action)
        console.log('【logger】执行完成后 state:', getState())
    }
    

    这样就实现了action -> reducer的拦截,所以每次触发 action 都能被 log 出来了。

    相关文章

      网友评论

          本文标题:redux中间件的理解

          本文链接:https://www.haomeiwen.com/subject/blbjihtx.html