最近公司举行 hackthon, 做了个棋牌类的游戏, 前端的主要技术栈就是 react + redux + redux-saga + socket.io
react 没什么可说的了,基本已经是前端标配了。本来 redux 作为 react 全家桶的一部分,也没什么可讨论的了。
但是redux-saga作为 redux 的神奇 middleware, 如果不熟悉 redux 的话, 很难真正理解 redux-saga, 所以顺路再梳理一下 redux 的使用方法和哲学。
上来先是一个官方文档redux
那么 redux 到底是什么呢?
先来看官方的一句话简介:
Redux is a predictable state container for JavaScript apps.
简单明了的说呢, redux 就是一个管理 state 的东西。
那么 state 又是什么呢?
state 我们可以理解为状态, 那 redux 是个状态机吗?
答案是, 可以这么理解。
除了 state,简介里还提到了一个至关重要的词 - predictable。
那么什么才算是 predictable 呢?
在 redux 的实现里, predictable 被实现成了 functional, 也就是俗称的 函数式。函数式编程这里就不多说了, 有兴趣的可以上网搜一搜, 相关的介绍很多。
那么 redux 又是如何做到 predictable 的呢?简单来说, 就是把所有可能更新 state 的操作都放到了 reducer 中, 通过 action 来驱动 reducer 做出不同的操作。并且 action 和 reducer 都是纯函数, 从而达到 predictable目的。
使用 redux 只需记住这三条原则, 就基本上可以使你的 app 达到一个 predictable 的状态。
single source of truth
一部分业务, 只维护一个数据源(也可以理解为,只是用一个 state)。
但并不是整个应用都要使用一个 state, 而是同一部分业务, 只使用一个数据源。
state is read-only
永远不要尝试直接修改你的 state, 如果要修改 state, 请触发 action, 让 reducer 去修改.
changes are made with pure functions
只使用纯函数来更新 state。
为什么要使用纯函数?
因为纯函数是完全可预测的。
redux 本身是个很简单的库, 最可贵的是提出了上面的三条原则, 并且在代码层面提供了执行这三条原则的结构和 api。
整个redux的执行流程, 可以用伪代码的形式来表达一下
creatStore -->
user interface --->
store.dispatch(action<Function>) -->
reducer<Function> to change the state and return new state -->
rerender view
接下来再看下在 redux 中, 是如何通过几个 api 来实现这个过程的:
createStore(reducer, preloadedState, enhancer)
源码在此,减去注释, 大概也就 100 多行代码。
顾名思义, 就是创建了个 store, 通过看源码, 我们可以知道这个 store 有以下几个方法:
combineReducers(reudcers)
在真实的开发环境中, 通常我们开发一个完整的应用, 在一些复杂的页面中, 不可能仅仅使用一个 state 就能完整的表达整个应用的状态, 这时多个 state 可能面对的就是多个不同的 reducer, 但是 createStore 这个 api 只能接收一个 reducer, 要怎么办呢?
这个时候, 我们就需要用到combineReducers了, 它返回一个 combination 方法, 在这个方法中, 会将传入的 reducers 逐个执行, 返回的是根据 reducer 的 name, 处理后的不同的 state。
bindActionCreators(actionCreators, dispatch):
通常一个应用中, 会触发很多 action, 这些 action 触发函数的集合, 就叫做 actionCreators。
另外, 在 createStore 中, 我们返回的 store 是带有 dispatch 方法的, 这个dispatch 方法就是 bindActionCreators的第二个参数。
这个 api 的主要作用就是连接了 store.dispatch 和定义的 actionCreators, 使触发的 action 可以在 redux 的 container 中执行。
compose(…funcs)
compose 返回一个高阶函数, 可以将 functions 从左到右按 reduce 的方式执行
代码非常简单, 看这里:
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)))
}
applyMiddleware(…middlewares)
在 redux 的执行流程中, 可能会有一些多个 reducer 通用的操作, 这个操作, 可以在 redux 的 flow 中, 执行 reducer 前执行 middleware。middleware 将以 reduce的方式逐个执行, 在 middleware 中可以获取 state 和 dispath 其他的 actionCreator。
通过这几个 api, 即可实现上面所描述的三条原则, 具体怎么实现, 我们将以接下来的 react-redux 为例, 展开说说。
之所以把 react-redux 放上来, 主要是为了看下 redux 的几个 api 在真实的开发环境中, 是如何使用的。
还是先来看看 react-redux 的 api 吧:
Provider
Provider实际上是一个 React Component, 它接收一个 props, 就是 redux 的 createStore 这个方法返回的 store