在 React 应用中,状态管理是一个没法绕开的话题,对于开发人员来讲,如何优雅地管理状态是一个比想象中要复杂的事情,是一门真正的开发艺术。前端
众所周知,React 应用是由一个个状态机组合而成, 组件是 React 应用的核心,状态则是一个或者多个组件的灵魂。对于一个成型的 React 应用来讲,组件构成了应用的骨架,而状态则是贯通全身的血液是应用充满活力和生机的关键。vue
随着应用的复杂化,要准确区分哪些组件须要状态将是一件无比困难的事情。若是将全部状态都存放在根组件,经过 context api
来消费状态未免不是一种简单的方法。但这并不能有效地解决问题,由于咱们不只须要经过 setState
细粒度控制状态变化,还要设计各组件间的状态通讯。一旦设计很差,状态的管理可能会变得混乱,状态的变化也会由于无迹可查而变得不可预测。react
Redux 做为社区最流行的状态管理方案,为咱们提供了可预测的状态容器。在 Redux 中,应用的状态被储存在一个 js 对象中做为单一数据来源,能够随时被获取。将咱们的注意力集中在这个对象上,排除了其余环节的开发和维护成本。而且应用的状态是“只读”的,不能直接修改状态。修改状态的惟一方法是派发(dispatch)相应动做(action)交由相应的纯函数(reducer)来更新状态,而后返回一个全新的状态对象交由页面渲染。git
经过上述约定,在 Redux 中,每个状态的更改都是有迹可循,有据可查,这对咱们状态管理的编程体验和代码维护以及后期 bug 排查极其重要。Redux 自己做为一个订阅发布系统,具体的内部处理流程以下:github
Redux 确实将状态管理简单化,合理化,但做为一个精简的库,它却有着陡峭的学习曲线,使人望而生畏的函数式编程概念和使人一头雾水的概念,让众多开发者望而却步。并且在实际的开发中,Redux 的开发和维护也是一件很繁琐麻烦的事情。vuex
Rematch 的做者 Shawn McKay 曾在 《Redesigning Redux》 中对 Redux 提出了 6 个可改进之处,但具体可归纳为如下 3 点:npm
上述问题看似日常,但与咱们平时的状态管理息息相关。由于这些问题,Redux 不但不会提升咱们的工做效率,甚至会下降工做效率。但 Redux 的状态管理思想是正确的,实际的项目也须要这种思想。所以为了更好地使用 Redux,下降其学习和使用成本,咱们急切须要基于 Redux 的最佳实践。编程
随着 Redux 使用程度的加深,其暴露出的工程化问题就越发严重。社区内存在很多解决 Redux 工程化问题的方案,其中 Dva 可谓是最亮眼的那颗星,被业界称为是基于 Redux 的最佳实践。redux
Dva 是基于 Redux 现有应用架构(redux + react-router + redux-saga 等)的一层轻量封装,帮咱们自动化处理了 Redux 架构中繁琐的步骤,好比样板代码维护、store 的建立和中间件的配置,将原来那些恶心、繁琐、容易出错的步骤掩藏起来,用简洁明了的 api 来进行配置和控制。api
函数式编程概念繁多
这部分问题主要集中 Redux 的初始化上,Dva 经过基于对象配置的方式解决初始化函数组合的问题,具体如图:
样板文件
在样板文件上,Dva 只解决了 reducer 和 redux-saga 样板文件的自动化管理,并无解决 action 的样板文件管理,所以这也算 Dva 的一个缺点吧。
model 是 Dva 的重要概念,对 Redux 社区有着不小的影响,它将 Redux 下的每个子状态的下的 state、reducer 和 sagas 都写在一块儿,经过对象配置的方式使 Redux 样板文件的管理思路清晰简单。下面是一个简单的例子:
Dva 将 action 分为同步 action 和 异步action,同步 action 的处理方法定义在 reducers 属性中,是惟一能够更新状态的地方。异步 action 的处理方法定义在 effects 属性中,同时也能够派发同步 action。
在注册 model 时,Dva 会按照 reducers 中定义的方法建立 reducer,按照 effects 中定义的方法建立 saga 反作用。
异步处理问题
在异步动做的处理问题上,Dva 选择了 redux-saga。Redux-saga 能够更容易管理反作用,执行更高效,测试更简单,在处理故障时更容易。经过 generator 来定义处理异步方法,让异步的流程更易于读取和写入,而且能够很容易地测试异步流程并保持 action 是纯洁性。
插件机制
在解决 Redux 工程化问题的同时,Dva 提供一套灵活的插件机制,让开发者能够深刻 redux 数据流处理的每一部分,进一步提升代码的灵活性和工做效率。
即便被奉为最佳实践,Dva 依旧也由于客观因素和局限性存在如下缺点:
actionTypes
,actionCreators
相关维护Dva 以后,社区出现了许多基于 Redux 封装的状态管理框架,但大多存在不小的局限性,甚至倒退,直到 rematch 的出现让人眼前一亮。rematch 是一个受 Dva 启发,零 boilerplate 的 Redux 实践,风格与 vuex 类似。
rematch 一样采起配置化 + model 的方案,将 redux 的实践,封装的更加简单。在设计上,rematch 与 Dva 仍是有些不一样的,咱们来看一个完整的例子:
rematch 与 Dva 的不一样在于,rematch 只是一个状态管理框架,只负责状态管理,其余一律无论,没有内置过多的库。而且建立应用步骤更少,减小了无谓的过程式调用,能经过配置毫不调用函数。
在总体使用风格上,rematch 更加轻便,将 redcuer、saga 和 action 统一使用 model 维护,redcuers 的定义更是合二为一,在定义 reducer 的各 action 处理方法时,便将对应的 actionCreator
和 actionType
定义下来,同时能够经过对象属性访问直接派发 action,减小了样板代码,极大程度上下降咱们的代码成本。
在异步问题上,rematch 使用 async/await
替代了redux-saga
和 thunk
方案,下降了异步动做处理的理解和使用成本。
在插件生态上,rematch 拥有相对较强的插件生态概念,将经常使用的 reselect
、persist
、immer
等都集成为了插件。在数据缓存,性能优化,开发体验优化都有进一步施展的空间,毕竟拥抱插件生态是一个良好的发展方向。
从 Redux 到 Dva 再到 rematch,咱们能够看到 Redux 开发从刀耕火种到自动化的进步,状态管理变得简单高效,但总归来讲,最佳实践方案基本上都是对 Redux 进行封装,在提供更简单的 API 的同时又不失任何可配置性的特色。
在看到社区的进步时,同时咱们也感觉到一丝无奈。无奈何处?那就是看着这么香,这么高效的工具,想从已有状态管理框架迁移至新的管理框架却存在不小的鸿沟。好比咱们想从 Redux 现有应用架构(redux + react-router + redux-saga )切换至 rematch,则必须舍弃 redux-saga,改变咱们原有的异步处理方案,存在不小的迁移成本。 所以形成了目前新项目自动化,老项目累死累活的局面。这不是咱们想看到,也是不肯意看到的状况。
rematch 启发于 Dva,可谓已经将 Redux 封装到极致,但这却只是对 Redux 工程化问题的解决,而在实际的状态管理的业务代码上依旧有着客观的优化空间,好比说:批量建立 action 处理方法。
唐刀
为了使尽量多的项目(不管新老项目)都能用上与 rematch 同样的的状态管理框架,最大可能地提高研发效率,下降研发代价,咱们决定从新打造一个基于 Redux 的状态管理框架。
咱们猫眼前端团队对社区已有方案并结合实际状况进行了长时间地调研和分析,决定保留 Redux 现有的应用架构(redux + react-router + redux-saga ),达成较低的学习和上手成本,能够与原生 redux 数据流管理并存,Dva 状态管理框架无缝迁移,rematch 快速迁移的目标。而且将 react hook 归入后续规划,准备打造基于 react hook 版的状态管理周边生态,进一步提升状态管理能力。
通过长时间开发与屡次优化,咱们终于打造出一款符合上述要求,并在业务代码有必定优化的状态管理框架—— 唐刀。
唐刀是一款汲取 Dva 和 rematch 精髓的数据流管理工具,作到了零 boilerplate,插件生态丰富,能够与原生 Redux 数据流管理方式共存,Dva 项目无缝迁移,rematch 项目快速迁移,并在业务代码上做出了可观的优化,极大地提升了状态管理效率。咱们来看下,唐刀完整例子:
为了达到 Dva 项目无缝迁移,唐刀在设计理念和 api 设计上基本与 Dva 保持一致,平移支持了 Dva 的核心功能,并针对 dva 的不足进行了修正与补充,下降 dva 用户的学习和上手成本。在样板管理和 action 派发上借鉴了 rematch,为 Dva 项目和 rematch 项目快速迁移至唐刀提供了可能和保证。
Generator 与 async/await 的抉择
在框架的高度封装下,对于用户来讲 Generator
与 async/await
只是语法糖上的区别,写法不一样但功能一致,sagas 反作用的建立由唐刀内部实现,开发者对此是无感知的。所以,对于 rematch 用户,这部分只是在写法上的不一样,不须要作过多的改动,除此以外没有其余的不一样。
初始化
为了能够与 Redux 数据流管理方式并存,在初始化时,唐刀提供了相关属性用以配置 redux 架构中的各类工具。这样即可以达成先接入,后改造的局面。具体以下:
经过属性配置,你彻底不用去关心和理解这些属性的实际调用过程,保证了快速接入项目的可能性。
插件
唐刀也是积极拥抱插件生态,在将来咱们还准备打造基于 react hook 丰富数据流管理的周边生态,目前唐刀内置并提供了如下插件:
在状态管理的相关业务代码上,针对写法相同,只是更新属性不一样的 action 处理方法,唐刀提供了批量创造 action 处理方法的属性,让你的 model 代码变薄,少写更多的代码。具体以下:
从上述对比能够看出,唐刀不只要把状态管理简单化,高效化,还要尽量兼顾到已有方案的迁移,让尽量多的项目拥抱简单高效的状态管理。在这一过程当中,咱们没有贬低任何方案,尽量作到取百家之长,以更低的学习成本,更少的样板代码和更少的学习成本,来拥抱 Redux 背后的简单哲学。
若是你还在备受 redux 架构或者其余状态管理工具的折磨,那么不防尝试一下唐刀,说不定它会给你带来意想不到的收获,心动不如行动,早用早解脱。
最后的最后,小编卖身求 star,小哥哥小姐姐们给我点它!
Github:github.com/MaoYanTech/…