深入浅出 redux
概论
- 基本原则
- 设计思路
- 实现流程
- 基础流程中部分的理解
- reducer
- action
- dispatch
- state
- 添加 middleware 和 enhancer 的流程
- 这个库面对的用户(高级,中级,低级)
- 如何作为一个产品来理解这个设计
redux 基本原则
分别为
- 单一数据源
- 即在一个使用 redux 的应用中,只有一个数据来源来驱动整个app 的 UI 的变化
- 通过 createStore 方法来创建一个闭包变量
- state 只读
- state 变量本身是一个不可变的对象,在实现的过程中也是这样的,通过将 state 放在一个闭包中,使其不可变,但是有一个问题,即 state 中的子数据其实是可变的
- 使用纯函数修改
- 什么是纯函数 — 即一个在稳定输入一个固定值会输出一个对应固定值的函数。
- 这个纯函数即为 reducer ,接受一个之前的旧 state 和 action ,返回一个新的 state
设计思路
redux 总得设计是一个数据流的管理工具。但是怎么定义数据流的权利是在用户的手里,数据流包括哪些的环节呢,数据存储?数据组织?数据流转?数据绑定?数据渲染?数据流程其实也是非常的长,多且杂的。所以要使用 redux 去做什么,并没有强制性的约束,那么我理解的redux 做的约束就是它的三大原则,这是给用户划定的框框,强制性的。那么在这样的基础上,redux 给用户还提供了什么了,我的总结是redux 还给用户提供了,三个层面的『武器』。这三个层面的「武器」,方便大家理解我把它们分别叫做常规武器,战术武器,和战略武器,首先分别简单介绍一下这三种武器:
- 常规武器就是 action + reducer 这一套最简易的改变数据的基础流程,没有它们 redux 的整个数据流转过程不复存在
- 战术武器就是 middleware ,每一个middleware 中都有获取 getState 和 dispatch 两个方法的权限,并且所有的 action -> 到 reducer 都会经过每一个 middleware
- 战略武器当然是最牛X的了,按照上面 middleware 的理解,enhancer 可以获取替换 state 以外所有的权限,可以修改和调用 store 的任何方法, 包括修改 replaceReducer 和 dsipatch 的方法
数据流程
严格的单向数据流是 Redux 架构的设计核心。
最简单的 redux 数据模型中数据流转会经过以下三个步骤:
- 通过调用
store.dispatch(action) 来发起一次 修改 state 数据的动作
- Redux store 调用传入的 reducer 函数,传入的有两个参数参数:当前的 action 和 原始的 state 树。注意 reducer 是纯函数,只用于计算下一个state 状态,所以不应该在 reducer 中发生任何产生副作用的行为,比如路由跳转或者 API 调用,这些应该在 dispatch action 之前发生
- Redux store 保存了根 reducer 返回的完整 state 树。
各个步骤分别依赖的部分是什么呢?
dispatch
- dispatch 中需要传入一个 action 对象
action
- action 日常中使用有这两种类型
- 一般是返回包含 type 字段和需要更新数据的对象
- 还有一种是使用了 redux-thunk 后,是一个返回可接受 getState 和 dispatch 为参数高阶函数, 然后如果存在异步操作,可以在异步操作中调用 dispatch 函数(redux-thunk 为一个 redux 的 middleware,因为在 middleware 中有访问 getState 和 dispatch 的权限
reducer
- 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。因为之前应用中会通过使用
combineReducers 方法将整个应用中的 state 拆分的各个子 reducer 进行数据处理,所以在处理完之后需要对所有的 reducer 输出进行整合
store
- store 就是一个包含上述对象,以及将他们流程串起来的对象。store 对象提供四个个基础的 API 供 用户使用。分别是
- getState()
- dispatch(action)
- subscribe(listener)
- replaceReducer(nextReducer)
store API
分别介绍一下四个 API 以及他们是怎么使用的吧
getState()
返回在 createStore() 中生成并且存储的 state 数据,简单来说就是获取全局数据的接口
dispatch(action)
分发 action ,这是触发 state 变化的惟一途径。执行 dispatch 会做两件事情:
- 执行当前的 reducer 方法
- 触发 subscribe 中监听的方法
执行 当前 dispatch 的返回值为传入的 action
subscribe(listen)
添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。
在 subscribe 中调用 dispatch 方法的时候需要注意的事项
- 一定要设置特殊的触发条件,如果无条件触发 dispatch 会导致死循环
- 无论是调用 subscribe 方法,还是调用 subscribe 方法,都会另存一份 listeners ,这样做是为了保证如果在 某一个 listener 中调用了 dispatch 后会修改 listeners 就会导致与预期不一样。这样这次调用 dispatch 都是对的,到下次 dispatch 才会生效
- 保证所有的监听器都注册在 dispatch() 启动之前,这样,在调用监听器的时候就会传入监听器所存在时间里最新的一次 state。
replaceReducer(nextReducer)
替换 store 当前用来计算 state 的 reducer。
这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。在实现 Redux 热加载机制的时候也可能会用到。
$$observable
redux 中的 createStore 中也暴露 observable 这个方法,此方法提供了个包裹 store 中 subscribe 的方法。
redux 基础 API
在介绍 middleware 之前, 我们首先要介绍一下 redux 的基础 API ,因为在 实现的 redux-middleware 的机制里, redux 的基础 API 非常重要。
- createStore
- combineReducers(reducers)
- applyMiddleware(...middlewares)
- bindActionCreators(actionCreators, dispatch)
- compose(...functions)
createStore
上面讲到了 store 提供的 API, createStore 就是这样一个创建 store 的一个 方法。
createStore 接受三个参数,分别是
- reducer (Function): 接收两个参数,分别是当前的 state 树和要处理的 action,返回新的 state 树。
- preloadedState (any): 初始时的 state。 在同构应用中,你可以决定是否把服务端传来的 state 水合(hydrate)后传给它,或者从之前保存的用户会话中恢复一个传给它。如果你使用 combineReducers 创建 reducer,它必须是一个普通对象,与传入的 keys 保持同样的结构。否则,你可以自由传入任何 reducer 可理解的内容。
- enhancer (Function): Store enhancer 是一个组合 store creator 的高阶函数,返回一个新的强化过的 store creator。这与 middleware 相似,它也允许你通过复合函数改变 store 接口。
combineReducers(reducers)
combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore 方法。
applyMiddleware(...middlewares)
使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。Middleware 可以让你包装 store 的 dispatch 方法来达到你想要的目的。同时, middleware 还拥有“可组合”这一关键特性。多个 middleware 可以被组合到一起使用,形成 middleware 链。其中,每个 middleware 都不需要关心链中它前后的 middleware 的任何信息。
它接受一个由 middleware 排序而成的数组作为参数:
** 参数 **
...middleware (arguments): 遵循 Redux middleware API 的函数。每个 middleware 接受 Store 的 dispatch 和 getState 函数作为命名参数,并返回一个函数。该函数会被传入 被称为 next 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用 next(action),或者在其他需要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store 的 dispatch 方法作为 next 参数,并借此结束调用链。所以,middleware 的函数签名是 ({ getState, dispatch }) => next => action。
bindActionCreators(actionCreators, dispatch)
将静态的不能执行的 action 对象转换为可以调用的方法
参数
- actionCreators (Function or Object): 一个 action creator,或者一个 value 是 action creator 的对象。
- dispatch (Function): 一个由 Store 实例提供的 dispatch 函数。
返回值
- (Function or Object): 一个与原对象类似的对象,只不过这个对象的 value 都是会直接 dispatch 原 action creator 返回的结果的函数。如果传入一个单独的函数作为 actionCreators,那么返回的结果也是一个单独的函数。
compose(...functions)
从右到左来组合多个函数。
这是函数式编程中的方法,为了方便,被放到了 Redux 里。
当需要把多个 store 增强器 依次执行的时候,需要用到它。
参数
- (arguments): 需要合成的多个函数。预计每个函数都接收一个参数。它的返回值将作为一个参数提供给它左边的函数,以此类推。例外是最右边的参数可以接受多个参数,因为它将为由此产生的函数提供签名。(译者注:compose(funcA, funcB, funcC) 形象为 compose(funcA(funcB(funcC()))))
middleware 和 enhancer 什么区别,什么关系

首先看一下上面这张图,applyMiddleware 本身也是一个创建 enhancer 的函数,相当于在 applyMiddleware 中拥有几乎对 整个store 的所有权限,如图所示,不仅可以访问 dispatch ,getState 等等 store 的 API ,还可以修改这些 API, 除了不能直接修改 state 外,几乎拥有了全部的权限,所以 enhancer 是一个拥有很高权限的插件方式,可以创造很多功能强大的工具,比如 devTools 可以知道整个的 action 流程并且记录下来。
middleware 就更加常见了,比如我们最常用的 redux-thunk, redux-logger 等等,他们都是通过由 applyMiddleware 传递 store 的 getState 和 dispatch 来实现,对 dispatch 的封装和修改的,进而拦截所有的通过 dispatch 的调用。
redux 的设计哲学
如上图中所设计的那样,我对整个redux 的理解就是,他提供了一套开放而约束的流程体系,让开发者尽量不去跨越这些流程获得更大的权限,比如 enhancer ,middleware 的设计,是非常精巧的,也是符合我们日常开发中的分层的概念
深入浅出 redux
概论
redux 基本原则
分别为
设计思路
redux 总得设计是一个数据流的管理工具。但是怎么定义数据流的权利是在用户的手里,数据流包括哪些的环节呢,数据存储?数据组织?数据流转?数据绑定?数据渲染?数据流程其实也是非常的长,多且杂的。所以要使用 redux 去做什么,并没有强制性的约束,那么我理解的redux 做的约束就是它的三大原则,这是给用户划定的框框,强制性的。那么在这样的基础上,redux 给用户还提供了什么了,我的总结是redux 还给用户提供了,三个层面的『武器』。这三个层面的「武器」,方便大家理解我把它们分别叫做常规武器,战术武器,和战略武器,首先分别简单介绍一下这三种武器:
数据流程
严格的单向数据流是 Redux 架构的设计核心。
最简单的 redux 数据模型中数据流转会经过以下三个步骤:
store.dispatch(action)来发起一次 修改 state 数据的动作各个步骤分别依赖的部分是什么呢?
dispatch
action
reducer
combineReducers方法将整个应用中的 state 拆分的各个子 reducer 进行数据处理,所以在处理完之后需要对所有的 reducer 输出进行整合store
store API
分别介绍一下四个 API 以及他们是怎么使用的吧
getState()
返回在
createStore()中生成并且存储的 state 数据,简单来说就是获取全局数据的接口dispatch(action)
分发 action ,这是触发 state 变化的惟一途径。执行 dispatch 会做两件事情:
执行 当前 dispatch 的返回值为传入的 action
subscribe(listen)
添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。
在 subscribe 中调用 dispatch 方法的时候需要注意的事项
replaceReducer(nextReducer)
替换 store 当前用来计算 state 的 reducer。
这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。在实现 Redux 热加载机制的时候也可能会用到。
$$observable
redux 中的 createStore 中也暴露
observable这个方法,此方法提供了个包裹 store 中 subscribe 的方法。redux 基础 API
在介绍 middleware 之前, 我们首先要介绍一下 redux 的基础 API ,因为在 实现的 redux-middleware 的机制里, redux 的基础 API 非常重要。
createStore
上面讲到了 store 提供的 API, createStore 就是这样一个创建 store 的一个 方法。
createStore 接受三个参数,分别是
combineReducers(reducers)
combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore 方法。
applyMiddleware(...middlewares)
使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。Middleware 可以让你包装 store 的 dispatch 方法来达到你想要的目的。同时, middleware 还拥有“可组合”这一关键特性。多个 middleware 可以被组合到一起使用,形成 middleware 链。其中,每个 middleware 都不需要关心链中它前后的 middleware 的任何信息。
它接受一个由 middleware 排序而成的数组作为参数:
** 参数 **
...middleware (arguments): 遵循 Redux middleware API 的函数。每个 middleware 接受 Store 的 dispatch 和 getState 函数作为命名参数,并返回一个函数。该函数会被传入 被称为 next 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用 next(action),或者在其他需要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store 的 dispatch 方法作为 next 参数,并借此结束调用链。所以,middleware 的函数签名是({ getState, dispatch }) => next => action。bindActionCreators(actionCreators, dispatch)
将静态的不能执行的 action 对象转换为可以调用的方法
参数
返回值
compose(...functions)
从右到左来组合多个函数。
这是函数式编程中的方法,为了方便,被放到了 Redux 里。
当需要把多个 store 增强器 依次执行的时候,需要用到它。
参数
middleware 和 enhancer 什么区别,什么关系
首先看一下上面这张图,applyMiddleware 本身也是一个创建 enhancer 的函数,相当于在 applyMiddleware 中拥有几乎对 整个store 的所有权限,如图所示,不仅可以访问 dispatch ,getState 等等 store 的 API ,还可以修改这些 API, 除了不能直接修改 state 外,几乎拥有了全部的权限,所以 enhancer 是一个拥有很高权限的插件方式,可以创造很多功能强大的工具,比如
devTools可以知道整个的 action 流程并且记录下来。middleware 就更加常见了,比如我们最常用的
redux-thunk,redux-logger等等,他们都是通过由 applyMiddleware 传递 store 的 getState 和 dispatch 来实现,对 dispatch 的封装和修改的,进而拦截所有的通过 dispatch 的调用。redux 的设计哲学
如上图中所设计的那样,我对整个redux 的理解就是,他提供了一套开放而约束的流程体系,让开发者尽量不去跨越这些流程获得更大的权限,比如 enhancer ,middleware 的设计,是非常精巧的,也是符合我们日常开发中的分层的概念