使用 React 进行领域驱动设计

Avatar of Adam Conrad
Adam Conrad

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

在 React 世界中,关于如何 组织前端应用程序 的指导非常少。(只需随意移动文件,直到“感觉正确”为止,哈哈)。事实上,我们可以做得更好。让我们看看您可以考虑用于构建网站架构的一种模式。

首先,您可能会将代码拆分为 /components 和 /containers 文件夹。这适用于小型网站,但当扩展到大型网站时,您会发现自己需要寻找更强大的东西。幸运的是,数十年的系统设计研究为我们提供了丰富的模式可供探索,以创建可扩展的架构。

其中之一是领域驱动设计,并且在过去几年中重新获得了普及。让我们探讨如何在 React 中使用它。

领域驱动设计的入门

领域驱动设计(DDD)是一种通过将软件应用程序的基础数据模型与领域逻辑相关联来管理软件应用程序复杂性的做法。这有点拗口,让我们进一步分解它。

领域是一种本体论,意味着事物在世界中是如何分组的。例如,单词joist与建筑施工领域有非常具体的联系。另一个词,比如Mike,可以属于多个领域,例如圣经人名领域(迈克尔的简称),或者与北约音标相关的政治领域。

当设计是领域驱动的时,这意味着我们将领域模型(例如,扑克领域中的扑克牌)放在上下文(例如,上下文分组,如游戏)中以帮助管理复杂性。

组织 DDD 网站

领域驱动设计专门用于处理随着网站添加越来越多的模型而带来的复杂性。对于只有一个模型的网站来说,它实际上没有意义。当您拥有大约四个模型时,就是开始考虑将模型绑定到多个上下文的好时机。这不是一个严格的规则,所以不要觉得您必须分解成多个上下文,但是一旦您拥有超过四个模型,这些上下文分组就会开始浮出水面。

从组织您的领域开始

让我们以 Twitter 作为我们的示例网站来进行组织。在 Twitter 中分离领域的一种方法是在为推文提供支持的博客平台和使微博传播和蓬勃发展的互动元素之间拆分我们的模型。

这是分离 Twitter 中关注点的唯一方法吗?绝对不是!DDD 的一个关键方面是创建领域没有唯一正确的方法。有很多方法可以拆分应用程序的边界上下文,因此不要过分关注我们选择的架构。相反,将此作为跳板来理解我们如何将DDD应用于前端代码的组织。

也就是说,我们的代码现在将被组织成如下所示(假设您从类似于 create-react-app 的东西开始)

twitter/
├── App.css
├── App.js
├── App.test.js
├── blog/
└── interaction/

在每个领域中定义组件和容器

现在我们已经设置了基本的文件结构,是时候添加一些真正的组件了!查看我们上面给出的领域 UML 图,从获取给定页面上数据的容器和组织构成这些页面的模板的组件开始会很有用。扩展我们的应用程序,我们现在有了以下结构(为简单起见,省略了相应的 test.js 文件)

twitter/
├── App.css
├── App.js
├── App.test.js
├── blog/
│   ├── HomePage.js
│   ├── TweetCard.js
│   ├── TweetDialog.js
│   ├── TweetList.js
│   ├── TweetListItem.js
│   ├── UserPage.js
│   └── UserCard.js
└── interaction/
    ├── FollowButton.js
    ├── LikeButton.js
    └── ShareButton.js

我们仍然保留 App 文件以将 React 初始化到我们的根级 HTML 标签。有了我们的领域,我们开始构建我们的容器(例如 HomePageUserPage)和组件(例如 TweetCardTweetListItem)。或者,我们可以进一步细分我们领域中的模型,如下所示

twitter/
└── blog/
    ├── user/
    │   ├── HomePage.js
    │   ├── UserCard.js
    │   └── UserPage.js
    └── tweet/
        ├── TweetCard.js
        ├── TweetDialog.js
        ├── TweetList.js
        └── TweetListItem.js

但是鉴于应用程序的大小,在这个阶段没有必要。

根据需要添加辅助函数

随着我们构建应用程序,我们的 UI 将继续变得越来越复杂。为了解决这个问题,我们有两种方法可以分离关注点并将逻辑从组件模板中提取出来:展示器实用程序展示器 将所有视觉呈现逻辑从模板中推出来,以使视图层尽可能保持简洁和简单。实用程序收集前端所有其他逻辑的共享功能,这些逻辑与模板没有特定关系。让我们更仔细地研究一下。

使用展示器清理模板

想想 Twitter 个人资料。在我的帐户上,您在这里看到了哪些元素?

有一些信息与我的用户直接相关:姓名、用户名、描述、位置、网站、生日、开始日期。还有其他模型之间关联的计数——有多少其他用户关注我?我关注了多少其他用户?还有一些页面上没有捕获的其他逻辑,例如我的推文、回复、媒体上传和我喜欢的內容。为了适当地捕获所有这些呈现逻辑,我们可以在文件树中添加另一个文件,以将展示器模式与 JSX 组件隔离

twitter/
└── blog/
    ├── user/
    │   ├── UserCard.js
    │   ├── UserCard.presenter.js

将逻辑推送到实用程序中

某些呈现逻辑非常基础,因此无论它是否在渲染中使用,在应用程序中都可能很有用。货币格式化、验证和时间戳格式化都是我们可以从应用程序中隔离的实用程序函数中获益的用例。它们在哪里?由于它们跨越了领域,因此实用程序可以位于它们自己的文件夹中

    twitter/
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── blog/
    │   ├── HomePage.js
    │   ├── TweetCard.js
    │   ├── TweetDialog.js
    │   ├── TweetList.js
    │   ├── TweetListItem.js
    │   ├── UserCard.js
    │   ├── UserCard.presenterjs
    │   └── UserPage.js
    ├── interaction/
    │   ├── FollowButton.js
    │   ├── LikeButton.js
    │   └── ShareButton.js
    └── utils/
         ├── currency.js
         ├── time.js
         └── validation.js

组织应用程序没有错误的方式!

最终,选择权在于您。这只是您可以安排应用程序的无数种方式中的一个示例。领域驱动设计是一种有价值的工具,因为它以有意义的方式分离业务逻辑,为开发人员之间创建更清晰的领域专业知识区分,并提供轻松组织和扩展代码的规则。

但是,如果您正在寻找 React 应用程序文件结构传统混乱的替代方案,请查看领域驱动设计。它可能是您需要的解决方案。

最后,如果你喜欢这种内容,并想了解更多关于前端、用户界面开发以及UX设计和研究(根据你在行业中的经验组织)的信息,我运营了一个你可能想查看的免费通讯