美文网首页
了解Redux源码

了解Redux源码

作者: 依然还是或者其他 | 来源:发表于2020-04-26 01:11 被阅读0次

    前言

    了解redux,最好可以结合一些其他的东西来里了解redux相关原理。
    如:

    • flux的一些思想
    • redux的源码.
    • 了解redux-thunk或者其他中间件
    • 了解react-redux,或者知道如何使用redux

    flux与redux

    flux是facebook提出的一种架构模式,而redux是实现了flux思想的一个库,但有点不一样。

    flux

    • actions:发送数据到dispatcher
    • dispacher:协调action与store,即将相应的动作发给相应的store
    • store:数据中心,可以存在多个store,所以需要dispatcher进行调度协调
    • view :视图


    redux

    • actions:将数据修改的动作告知reducer
    • reducer:纯函数,在reducer中进行数据的更新
    • store:数据中心,是唯一的数据中心
    • view:视图
      且redux应用的三大原则
    • 单一数据源
    • state只能是可读的
    • reducer是纯函数


    flux与redux

    redux库实现了flux的单向数据流,但redux是没有dispatcher的,因为redux只有唯一的一个store,不需要进行调度协调。
    在flux架构中,数据逻辑的处理是在各个store中进行的,各自处理各自的,通过调度来进行管理。
    而在redux中,数据逻辑的处理和更新是在reducer中进行,并且reducer是一个纯函数,不存在副作用,也更适合数据可追溯。

    redux源码

    redux源码版本4.0.1

    下面是使用redux的代码

    import { createStore, applyMiddleware } from 'redux'
    import thunkMiddleware from 'redux-thunk'
    import { createLogger } from 'redux-logger'
    import reducer from './reducer'
    const loggerMiddleware = createLogger();
    
    const store = createStore (reducer, applyMiddleware(thunkMiddleware,loggerMiddleware));
    

    从使用入口createStore开始

    export default function createStore(reducer, preloadedState, enhancer) {
        //enhancer 即applyMiddleware()返回的函数, 是一个高级函数
    
      //过滤传参错误 传参不合理的情况
      if (
        (typeof preloadedState === 'function' && typeof enhancer === 'function') ||
        (typeof enhancer === 'function' && typeof arguments[3] === 'function')
      ) {
        throw new Error(
          'It looks like you are passing several store enhancers to ' +
            'createStore(). This is not supported. Instead, compose them ' +
            'together to a single function.'
        )
      }
      //preloadedState可不传,若是只传入两个参数,第二个为函数,则enhancer = preloadedState
      if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
        enhancer = preloadedState
        preloadedState = undefined
      }
    
      if (typeof enhancer !== 'undefined') {
        if (typeof enhancer !== 'function') {
          throw new Error('Expected the enhancer to be a function.')
        }
       //如果使用中间件,那么enhancer会进入这个判断,
        return enhancer(createStore)(reducer, preloadedState)
      }
      // 其他代码...
      // 主要是dispatch 和 subscribe ,一般是其他库进行调用来实现发布订阅,如react-redux
    
      // 进行dispatch,对state进行初始化
      dispatch({ type: ActionTypes.INIT })
      return {
        dispatch,
        subscribe,
        getState,
        replaceReducer,
        [$$observable]: observable
      }
    }
    

    applyMiddleware

    export default function applyMiddleware(...middlewares) {
     // 这里就是enhancer
     // enhancer(createStore)(reducer, preloadedState) 其实就是返回的 {..store,dispatch}
     // 这里是用箭头函数写的,如果乍一看有点没太理解,可以捋一捋
      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)
        }
        //将中间件遍历一遍, chain 数组中 值 类似于函数 next=>action=>{}
        const chain = middlewares.map(middleware => middleware(middlewareAPI))
        //compose 进行函数组合
        dispatch = compose(...chain)(store.dispatch)
    
        return {
          ...store,
          dispatch
        }
      }
    }
    

    中间件redux-thunk

    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;
    
    

    梳理下

    //上面就是redux-thunk的源码
    //实际就是中间件就是这一部分
    ({ dispatch, getState }) => (next) => (action) => {
        if (typeof action === 'function') {
          return action(dispatch, getState, extraArgument);
        }
    
        return next(action);
      };
    }
    
    //将中间件遍历一遍时,都执行了一次,并返回,所以chain数组的里面的值就是类似于函数 next=>action=>{} 结构
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    
    //重点,中间件串联使用的关键
    dispatch = compose(...chain)(store.dispatch)
    
    

    先来看下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)))
    }
    

    梳理下

    如果 composeFn = compose(fn1,fn2,fn3,fn4);
    那么composeFn=fn1(fn2(fn3(fn4(x))));  
    
    

    下面是模拟compose和中间件 的例子

    const compose = (...funcs) => {
      return funcs.reduce((a, b) => (...args) => a(b(...args)));
    };
    
    function fn1(next) {
      console.log("1");
      return (action) => {
        console.log("11");
        return next(action);
      };
    }
    function fn2(next) {
      console.log("2");
      return (action) => {
        console.log("22");
        return next(action);
      };
    }
    function fn3(next) {
      console.log("3");
      return (action) => {
        console.log("33");
        return next(action);
      };
    }
    function fn4(next) {
      console.log("4");
      return (action) => {
        console.log("44");
        return next(action);
      };
    }
    
    let x = () => () => {
      console.log("xx");
    };
    let a = fn1(fn2(fn3(fn4(x))));
    
    let composeFn = compose(
      fn1,
      fn2,
      fn3,
      fn4
    );
    
    let b = composeFn(x);
    a();
    b();
    //结果是
    //4321 4321 11223344 11223344
    

    compose(...chain)函数将中间件从右向左进行了包裹,即上面的4321
    dispatch = compose(...chain)(store.dispatch) 执行得的了新的dispatch,即扩展后的dispatch,即上面的b。
    当用户发送action,action调用了扩展后的dispatch时,会发生从左到右的执行顺序,即11223344。这是因为中间件基本是这样的高级函数结构:next=>action=>{},当compose(...chain)(store.dispatch)执行时,最内侧的函数先执行将action=>{},作为参数传给了外层函数,即右则结果函数作为参数传递了左侧的函数,以此类推,所以当扩展dispatch执行时是从左向右的顺序。

    参考

    1.The difference between Flux and Redux——Samer Buna
    2.MVC vs Flux vs Redux – The Real Differences——Vinugayathri
    3.深入浅出Redux原理——呼吸
    4.redux之compose——limengke123
    5.带着问题看React-Redux源码——Nero

    相关文章

      网友评论

          本文标题:了解Redux源码

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