共计 3340 个字符,预计需要花费 9 分钟才能阅读完成。
前言
在学习了 React 之后,紧跟着而来的就是 Redux 了~
在系统性的学习一个东西的时候,了解其背景、设计以及解决了什么问题都是非常必要的。接下来记录的是,我个人在学习 Redux 时的一些杂七杂八~
Redux 是什么
通俗理解
https://www.zhihu.com/questio…
介绍
先从官方的一句介绍看起:
Redux is a predictable state container for JavaScript apps.(Redux 是 Javascript 应用程序的可预测状态容器。)
当然,假如你在这之前并没有接触过相关的状态管理库或者框架,看到这句话时是非常的懵逼的,不过可以带着这句话来一步步探索~
背景
随着 Javascript 单页面应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state(状态)。这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。— Redux 文档
上面这一大段引用概况起来就是一句话,state(状态)在什么时候什么地方,因为什么而变化成了一个不受控制的过程。(这不能忍,状态如果无法预测以及控制)
那么 Redux 就是试图让 state 的变化变得可预测。这些限制条件反映在 Redux 的三大原则中。
核心概念
1.Redux 使用普通的对象来描述 state,这个对象就是 Modal。
2. 要想更新 state 中的数据,你需要发起一个 action。Action 就是一个普通 JavaScript 对象用来描述发生了什么。
3. 为了把 action 和 state 串起来,开发一些函数,这就是 reducer。reducer 只是一个接收 state 和 action,并返回新的 state 的函数。
三大准则
只有一个 state 树。
state 是只读的,只能通过 action 改变。
reducer 是纯函数,没有副作用。
了解到这些后,其实已经多少能明白 Redux is a predictable state container for JavaScript apps.(Redux 是 Javascript 应用程序的可预测状态容器。)这句话,为什么是可预测的?因为只有一个 state 树,并且它是只读的,而且只能通过 action 来改变(改变的过程变得清晰可追踪),并且获取 state(状态)只能通过 reducer,而 reducer 是一个纯函数(此处了解 state 是重点),没有副作用,也就意味着我们能知道我们最终得到的 state 是什么样的。
api 简介
[createStore(reducer, [preloadedState], [enhancer])](https://www.redux.org.cn/docs… 创建 store 的函数,返回一个对象,包含 getStatedispatchsubscribegetReducerreplaceReducer 等方法
combineReducers(reducers) 合并多个 reducer
applyMiddleware(…middlewares) 中间件处理,在 实际的 dispatch 前调用一系列中间件,类似于 koa
bindActionCreators(actionCreators, dispatch) 绑定 action 和 dispatch
compose(…functions) 函数式编程中常见的方法,compose(funcA, funcB, funcC) => compose(funcA(funcB(funcC())))
React-redux
介绍
Redux 官方提供的 React 绑定库。具有高效且灵活的特性。
动机
React 是以组件化的形式开发。为了组件的复用以及代码的清晰,通常我们将组件分为容器组件以及 UI 组件。
关于容器组件和 UI 组件,推荐阅读该文章,而引入了 React-redux 可以很好的帮助我们分离容器组件和 UI 组件。
为什么选择 react-redux
react-redux 是官方提供的绑定库,由 redux 开发者维护,可以很好的与 redux 保持同步。
它鼓励组件分离。react-redux 协助我们分离容器组件和 UI 组件,通过提供 API 连接 store(提供数据)和 UI 组件,并且使得 UI 组件不需要知道存在 Redux(复用)。
性能优化。虽然 React 速度很快,但是 re-redering 是非常消耗性能的,而 react-redux 的内部做了许多性能优化。
社区支持,因为是官方指定的绑定库,所以拥有大量的使用者,社区活跃度高,问题也容易解决。
api 简介
<Provider store>
使组件层级中的 connect() 方法都能够获得 Redux store。store: 应用程序中唯一的 Redux store 对象
connect(mapStateToProps, mapDispatchToProps, mergeProps, options)
mapStateToProps(state, [ownProps]): stateProps: 映射 state 作为 UI 组件的 props
mapDispatchToProps(dispatch, [ownProps]): dispatchProps:映射 dispatch 作为 UI 组件的 props
mergeProps(stateProps, dispatchProps, ownProps): props: 如果指定这个函数,即合并 mapStateToPropsmapDIspatchToPropsoweProps 作为 UI 组件的 props
options: 定制 connector 的行为
Redux 存在的问题
与其说缺点,不如说是 Redux 的优势而造成的不可避免的劣势,问题应该辩证地看~
纯净。Redux 只支持同步,让状态可预测,方便测试。但不处理异步、副作用的情况,而把这个丢给了其他中间件,诸如 redux-thunkredux-promiseredux-saga 等等,选择多也容易造成混乱~
啰嗦。那么写过 Redux 的人,都知道 actionreducer 以及你的业务代码非常啰嗦,模板代码非常多。但是~,这也是为了让数据的流动清晰明了。
性能。粗暴地、级联式刷新视图(使用 react-redux 优化 )。
分型。原生 Redux-react 没有分形结构,中心化 store;
Redux 的最佳实践
vuex(dva)
事实上,如果用过 vuex 或者 dva 的话,个人觉得还是会比较偏向于这种用法。比起 Redux 的啰嗦,dva 帮忙简化了很多步骤。具体的实现后续补充~
这里先补充一点,vuex 不是 immutable,所以对于时间旅行这种业务不太友好。
Redux 的实现浅析
前言
Redux 的代码相对比较简单,容易理解,源码的解读推荐看这篇文章,本段主要是对代码里一些个人觉得比较有意思的点进行分析~
createStore
在这里看出,redux 即使是在内部,也是函数式编程~ 当我们传入了一个 enhancer 函数(即中间件),会把 createStore 本身当成参数传给 enhancer 然后返回一个新的函数来调用 即 fn => fn
暴露出的 subscribe 函数也是挺有意思的,首先是 isSubscribed 这个变量,其实就是一种非常基础的闭包使用,
然后是每次订阅或者取消订阅的时候,都会在 dispatch 之前保存一次快照,然后当前的 dispatch 用的是上一份快照,而下一个 dispatch 则是使用当前这一份的快照
compose
非常简洁的写出了函数式编程的一个常用函数 (…args) => f(g(h(…args))).
combineReducer
可以看出,每一次 action 都会重新计算所有的 reducer~ 但如果不是非常巨大的 state 树,并且拆分了很多模块,个人认为其实影响不大
bindActionCreator 和 applyMiddleware 相对容易理解,这里就不赘述啦