跳转到主文档

容器组件(Container)

前两个章节中,我们把项目中的业务逻辑拆分成了两个 layer,一个是【 视图组件 】,另一个是 【 业务模块 】。

【 视图组件 】 负责 UI 展示、交互等;【 业务模块 】负责实现 UI 无关的业务逻辑,专门管理状态,既可以是组件状态(局部,不唯一),也可以是应用状态(全局,唯一)。

components/Contacts/index.tsx 这样使用了 useModel API 的组件,其实已经在客户端应用架构中扮演一种新的角色,负责把 View 和 Model 这两个 layer 连接起来,类似传统 MVC 架构中 Controller 的角色,也类似一种 ViewController。

因为这种组件属于一种新的功能模块,在 Modern.js 里我们沿用习惯,把它们称作【 容器组件(Container)】。

容器组件推荐放在专门的 containers/ 目录里,我们执行以下命令:

mkdir -p src/contacts/containers/
mv src/contacts/components/Contacts/index.tsx src/contacts/containers/Contacts.tsx
rm -r src/contacts/components/Contacts/

修改 containers/Contacts.tsx 的代码:

import Item from '../components/Item';
import contacts from '../models/contacts';

修改 App.tsx 的代码:

import Contacts from './containers/Contacts';

重构完成,现在的项目结构是:

.
├── .vscode/
├── api/
│ ├── .eslintrc.json
│ └── contacts.ts
├── src/
│ ├── contacts/
│ │ ├── components/
│ │ │ ├── Avatar/
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ └── Item/
│ │ │ ├── index.test.tsx
│ │ │ └── index.tsx
│ │ ├── containers/
│ │ │ └── Contacts.tsx
│ │ ├── models/
│ │ │ ├── contacts.test.ts
│ │ │ └── contacts.ts
│ │ ├── styles/
│ │ │ └── utils.css
│ │ ├── App.css
│ │ └── App.tsx
│ ├── landing-page/
│ │ └── pages/
│ │ ├── comments/
│ │ │ └── [commentTitle]/
│ │ │ └── index.tsx
│ │ ├── _app.tsx
│ │ ├── docs.tsx
│ │ └── index.tsx
│ ├── .eslintrc.json
│ └── modern-app-env.d.ts
├── .editorconfig
├── .gitignore
├── .npmrc
├── .nvmrc
├── README.md
├── package.json
├── pnpm-lock.yaml
└── tsconfig.json

components/ 里的【 视图组件 】,都是目录形式,如 Avatar/index.tsx。而 containers/ 里的【 容器组件 】,都是单文件形式,如 contacts.tsx这是我们推荐的一种最佳实践

在​ 添加 UI 组件(Component) 章节提到过,【 视图组件 】用目录形式,是因为【 视图组件 】负责实现 UI 展示和交互细节,可以演变的复杂,用目录形式,可以方便增加子文件,包括专用的资源(图片等)、专用子组件、CSS 文件等,在这个目录内部可以随意重构,只考虑最小局部。

而【 容器组件 】只负责连接,是一个胶水层,复杂的业务逻辑和实现细节都交给 View 层和 Model 层去实现,【 容器组件 】自己应该保持简单清晰,不应该包含复杂实现细节,所以不应该有内部结构,采用单文件形式不但更简洁,也能起到约束作用,提醒开发者不要把容器组件写复杂。


本小节的代码可以在这里查看