应用架构
上一章节中,我们把硬编码的 mockData
改成从 BFF 加载,从 App.tsx
里拆分出了 components/AllContacts.tsx
和 components/ArchivedContacts.tsx
,在 AllContacts
组件里用 BFF 函数,获取到联系人数据之后,保存在 AllContacts
的组件内部状态里,而 ArchivedContacts
组件暂时继续使用 mock 数据。
本章节中,为了进一步实现项目功能,我们需要让 AllContacts
和 ArchivedContacts
都从 BFF 获取数据,还要实现【 Archive 】按钮,点击按钮能把联系人归档。
业务逻辑变复杂之后,相关代码不可避免会变多,如果都写在 AllContacts 组件或其他组件里,都会让这个组件的可读性和可维护性变差,让做不同事情的代码混在一起。
原本可以跟 UI 完全解耦的业务逻辑(比如网络请求、纯数据的操作、状态的管理等)跟 UI 逻辑(比如联系人列表如何展现)混在一起,当需要修改 UI 的时候,不得不跟 UI 无关的业务逻辑代码打交道,反过来也一样,不符合【 单一职责原则(SRP)】,也做不到【 关注点分离(SoC)】。
从这里开始,我们发现如果这是个真实的项目,继续这样写下去会产生越来越多面条式代码,仅凭 React 组件这一种抽象方式,不足以让代码足够结构化,随着项目不断积累业务逻辑、复杂性和变更,技术债也会积累,最终可能变成没人愿意碰的祖传代码。
像这样的项目,需要更健全的客户端应用架构。
Modern.js 提供开箱即用的应用架构,支持几种扮演不同角色(role)、属于不同分层(layer)的代码模块类型,可以把业务逻辑解耦到不同类型的代码模块里,做到高内聚低耦合。
之前介绍的 App.tsx
和 pages/
都是其中一种代码模块,通过在最顶层对客户端路由的管理,把其他代码模块最终组织到一起,形成应用。
当前项目里 components/
目录中的 React 组件,是一种可以称作【 视图组件 】的代码模块,负责 UI、交互上的界面展现。
本章节我们来把 AllContacts
组件中可以跟 UI 解耦的业务逻辑,移到一种叫【 Model(业务模型)】的代码模块里。