前言
redux 的源码是我阅读过的一些库的源码中,相对简单的。如果大家的感兴趣强烈推荐大家亲自阅读一下。
本文为了方便理解 抛开了一些容错处理以及边缘条件的判断。
combineReducers
combineReducers是 redux 中内置的工具函数,目的是将多个 reducer 函数合并为一个最终的 reducer 函数。这个最终的 reducer 函数可以用于 createStore 中作为参数。
下面两种写法是完全等价的。
combineReducers 的实现非常的简单。在 A 处首先对 reducers 对象进行遍历,排除 value 值的类型不是 function 的 value。
在 B 处,我们会遍历经过前一步过滤的 reducers 对象,依次的执行 reducers 对象中每一个 reducer 函数, 将返回的结果存储在新的对象 nextState 中,最后返回新的对象。
createStore
createStore, 会创建一个 Store, 存放应用中全部的 state, 形成 state 树。
另外 Store 会提供额外的四个方法。getState 获取 Store 存储的 state 树;dispatch 分发 action 更改 Store 中的 state;subscribe 注册监听器会在 dispatch 时触发;replaceReducer 替换用来计算 state 的 reducer。
createStore, 接收 3 个参数:
- reducer,负责处理 action,返回新的 state 树。
- preloadedState,初始的 state。如果是通过 combineReducers 创建 reducer,初始的 preloadedState 的 keys 必须与 reducers 对象保持一致。
- enhancer,store 增强器,enhancer 是一个高阶函数,返回值是一个经过包装的强化的 store。而 redux 的 applyMiddleware 本身就是一个 enhancer。
dispatch
dispatch 将会用来分发 action, 更新 currentState 对象。在更新完成后,同时会更新 currentListeners,并依次执行监听者列表。
getState
replaceReducer
使用新的 reducer 替换现有的 reducer,同时执行dispatch({type: ActionTypes.REPLACE})(ActionTypes.REPLACE 是随机的字符串)。初始化 state。
subscribe
subscribe 会为 dispatch 注册监听器,监听器存储在 nextListeners 数组中,subscribe 返回的函数则会注销监听器。
compose
compose 并不是 redux 中的概念,而是函数式编程中概念。类似的方法在 ramda 等工具库均有实现。
从右往左执行函数组合(右侧函数的输出作为左侧函数的输入)。最右侧函数可以是多参函数,其余函数必须是单参函数。类似 a(b(c(arg)))。
middleware
redux 的中间件的模型类似与 koa。在 next 前面以及 next,由外向里依次执行。当最里层的 next 执行完成后,next 后面的代码,会由内向外依次执行。非常类似 koa 的洋葱中间件模型。
以下是一个简单的 redux 中间件的示例。
下面是 redux 文档中, 为介绍中间件的原理而给出的 applyMiddleware 的 单纯的实现。
中间件会对 dispatch 进行一层包装,并且总是会返回包装后的 dispath。下一个中间件,会基于上一个中间件返回的 dispatch 再次进行处理。
applyMiddleware
在前面我们说过 applyMiddleware 是 redux 内置的 enhancer。我们先来回顾一下 enhancer 的使用方法。
在 createStore 中调用 enhancer。参数为 createStore 自身,enhancer 会返回一个新的函数。接收 reducer, preloadedState 对象作为参数。
在 applyMiddleware 中,利用 js 的闭包的特性使用 createStore 以及 reducer, preloadedState 参数创建 store。
使用 管道 compose,将 store.dispatch 逐层的进行包装????,返回的 dispath 会覆盖 store 中 dispatch。
bindActionCreators
bindActionCreators 在平时工作中出镜率很少,bindActionCreators 主要用处是将 dispatch 方法包装到 action creator 中。bindActionCreators 的源码很简单。下面是具体实现。