了解Redux源码

2020-04-26  本文已影响0人  依然还是或者其他

前言

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

flux与redux

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

flux

redux

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

上一篇下一篇

猜你喜欢

热点阅读