JavaScript 须要管理比任什么时候候都要多的 state (状态)编程
state 在何时,因为什么缘由,如何变化已然不受控制。redux
经过限制更新发生的时间和方式,Redux 试图让 state 的变化变得可预测。设计模式
action => middleware => reducer(s) => Store闭包
这是redux提供的几个关键文件和它们的做用,其实简单他们提供的功能不难发现他们函数式编程的影子。redux里面设计比较巧妙的点我的感受是在中间件里。middleware在redux中被设计为在action发起后,到达reducer以前的拓展点。咱们能够利用middleware实现相似日志记录,错误定位或者路由,还有异步处理action这些操做。app
redux的源码是比较典型的FP风格,掌握一些基本FP概念,再去阅读redux源码会轻松不少异步
Higher order functions can take functions as parameters and return functions as return values.函数式编程
接受函数做为参数传入,并能返回封装后函数。函数
Currying > Currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument学习
是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数的技术。 add(1,2,3) => add(1)(2)(3)this
Compose > Composes functions from right to left. 组合函数,将从右向左执行。
compose(subtract,multiple,add)(200) 等同于 subtract(multiple(add(200)));
内部使用reduce,而不是直接嵌套。
store.dispatch(action) => middleware =>reducer => store
贴上实现单向数据流的关键源码(部分删减)
dispatch函数的实现 (/createStore.js)
isDispatching
变量用来控制在reducer函数执行过程当中不容许再次dispatch,这个过程用try/finally提供可靠性;第十行取得当前监听器函数列表的快照,在for循环中依次执行,这里执行也是有讲究,并无直接
listener[i]()
调用,而是采用了分割this的行为逐个调用监听器函数。总结这个dispatch函数关键点以下
combineReducer函数的实现(/combineReducers.js)
中间件发挥做用的时间点在派发action后,达到reducer前,能够理解为在调用原生dispatch(action)前,使用了中间件。 与其按照时间节点来理解,倒不如说中间件是为了加强dispatch函数而作的设计 applyMiddleware的源码很是精炼
这里声明了一个middlewareAPI,经过里面的getState方法就能够拿到store里的数据,另一个dispatch并无什么实际的做用,就算调用了,它也会告诉你不能使用,这里利用map将middlewareAPI传入到每一个中间件里,构造了一个闭包,让中间件能够访问到state数据,这里也利用了currying函数延迟执行的特性,它接受了参数执行可是返回的是另一个待执行的函数。 如此就保证了每一个中间件能够获取到state,关键点在于中间件科里化的设计,让其能够延迟执行和参数复用。
const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) }
// 利用currying函数延迟执行的特性
复制代码
如何将中间件串联起来,并保存最后一个函数传入的参数为store.dispatch 想实现这个特性就要用到compose组合函数, 将中间件串联起来,而且最后一个函数入参为store.dispatch, 传入的next就是下一个中间件,固然最后一个函数接受的next就是原生的store.dispatch,那个时候中间件就处理完毕,将action派发到reducer了。
const a = next => action => next(action)
const b = next => action => next(action)
const c = dispatch => action => dispatch(action)
compose(c, b, a)(store.dispatch)
// 源码实现 dispatch = compose(...chain)(store.dispatch)
复制代码
函数签名middleware = store => next => action => { next(action) }
其实看到这里应该也大体明白了为何要这么设计中间件,返回的第一个函数是为了保证中间件能够取到全局状态,返回的第二个函数是为了保证中间件能够依次调用。redux里的中间件是一个科里化的函数,其主要目的是为了利用其延迟计算和参数复用的能力,来实现中间件的众多特性。
redux虽然为咱们解决了state的管理问题,但依然不是百分之百的完美。逻辑上redux提供了一套简单可行且很是清晰规范的state管理方案,数据的单数据流和其三个原则,与之带来的是会写一些模板代码,若是使用了中间件,特别是redux-saga那种独立规范特别多的中间件,会耗费咱们不少的时间在写模板上,虽然咱们能够对数据流动掌控的特别精细,可是时间成本依然减缓了咱们开发的效率。
redux的改进应该在保留优点设计,解决痛点的基础上进行。其实在多数开发者使用redux时通常会对其作简单的封装再使用,对redux增长一些设计模式或是使用企业内部的diapatch加强方法,这里抛砖引玉,提出几个redux理想改进的几个须要注意的地方