React DDD useReducer vs useState

之前因为删除大量文章,创作等级降了一个大等级,由于正在弄东西憋大招,所以发篇比较深入的文章,希望能够养一下号

我们知道,充血模型(状态逻辑)一定比贫血模型(状态管理)好

为什么?因为贫血模型不反映逻辑

贫血模型是领域设计中的一个大陷阱,它已经不是 bad smell 不 bad smell 的问题了,而是已经彻底背叛了领域开发

领域驱动设计不只是为大架构上开发特大型项目提供可能性

更是简化大家的思维模型,提升大家的开发效率,把前端开发直接引入到下一个时代

而贫血模型,就是这个前进道路上最大的敌人

首先,我们来看一下开发过程和功能设计过程的隔阂:

需求设计 ——> UI设计 ——> 交互设计 ——> 组件设计 ——>组件功能设计

这是大家在 vue2/react 16.8-/AngularJS 下的开发流程

这个流程有非常大的问题 ——

前端开发过程严重背离需求

需求到前端这里的时候,已经过了很多环节,需要前端倒推出需求逻辑,再翻译成组件代码

如果加上了单元测试,工作时的思维切换过程是这样的

业务逻辑(需求设计)——> 视图逻辑(UI设计)——> 代码实现逻辑(组件开发)——> 业务逻辑(单元测试)

开发过程中,前端开发人员的思维模型频繁切换,统一语言形同虚设

如果出现业务变更或者实现有误,这里的逻辑箭头将会从单向变为双向

遇到稍微复杂点的应用,我们团队有过统计 ——

60%的精力花费在沟通和思维切换(以及这样的大脑负荷带来的懈怠)

35%的精力花费在跨组件逻辑复用

5%的精力花费在真正的逻辑开发上

浪费掉了整整90%以上的效率,这是对社会工时的巨大浪费!!!

是的,可以用第三方,但是第三方给你带来的方便,也会导致第三方开发人员有更大的工作负荷和工时浪费

理想的前端工作流程是怎样的?

业务逻辑(需求设计)——> 业务逻辑(领域开发)——> 业务逻辑(领域测试)——> 代码实现逻辑(组件开发,UI设计)

视图只是一层皮!

没有MVVM,没有MVP,没有MVC

只有DOM适配器!

你不是中介,dom不是楼盘,model也不是客户,他们不会永远没有交集

你犯不着用中介模式这种跨平台的方式解决并非跨平台的问题

框架实现是MVVM,那是框架的事情,你只需要把它想象成适配器就可以了

因此,你只写逻辑,完全脱离组件的时候 ——

充血模型才是你的最佳选择

我们来看看 DDD 的完整表述:

, password: "", }; function useService() { // react's service token const Context = createContext<{ state: any; dispatch: Dispatch<any> }>({ state: defualtValue, dispatch: () => {}, }); const [state, dispatch] = useReducer( (innerState: any, action: { type: string; payload: any }) => { // ... return innerState; }, defualtValue ); return { Context, state, dispatch }; } function Compo() { const Service = useService(); return ( <Service.Context.Provider value={{ state: Service.state, dispatch: Service.dispatch }} >Service.Context.Provider> ); }

注意,服务返回 Context 是最佳实践,领域实体必须包含 id(token、context)

但是相同的内容,用 useState 如何?

function useService() {
  // react's service token
  const Context = createContext<any>(null);
  const [name, setName] = useState("");
  const [password, setPassword] = useState("");
  return { Context, name, setName, password, setPassword };
}

function Compo() {
  const Service = useService();
  const Context = Service.Context as Context<typeof Service>;
  return <Context.Provider value={Service}>Context.Provider>;
}

为什么一定要为难自己,去用一个——不成熟,无指导,更繁琐,更痛苦——的方案呢?

别提不变性,响应式 hooks 比 useReducer 纯得多得多

并且,useReducer 的写法在js下支持烂的一皮,如果真的喜欢这种可预测方式,可以采用reasonml,js/ts 不适合 useReducer 的使用

那可预测怎么办?

当你的服务脱离组件单独存在,你本身就不能相信浏览器调试

单元测试在此时成为必选项

因此,给出一个架构结论:

TDD和DDD是孪生兄弟,没有DDD不用TDD,反之亦然!

因为你没有组件可以依靠,同时你的服务返回的内容又非常单一,本身测试友好

这就是全新的开发模式,不论你习不习惯,我都通过自身的体验,坚定地相信这是未来

没有任何一家企业能够拒绝十倍的效率提升,90%的成本缩减

这还没算上 DDD 统一语言能够跨过产品,设计,前端,后端,算法,大数据的职能限制,直接提升的全技术栈沟通效率

最后给个结论 ——

useState 完全优于 useReducer,在 React 新版本,配合 DDD 开发方式,你完全不要考虑 useReducer 这个 API

最后,附上 阿里 的 DDD 释义文章:

阿里巴巴淘系技术:阿里技术专家详解DDD系列 第二讲 – 应用架构zhuanlan.zhihu.com图标