什么是 Angular 开发中的 Dumb components

Dumb components,在 Angular 开发中也被称为 Presentational components,它们的主要职责是通过展示数据和触发事件,把业务逻辑和 UI 表现分离开来。Dumb components 只通过 @Input() 接收数据,@Output() 向外发送事件,不负责处理任何业务逻辑,这些逻辑由 Smart components 或服务来承担。这是典型的单一职责原则的实现,能够提高代码的可维护性和可测试性。

Dumb components 的核心思想是让组件尽可能地简洁,只负责渲染自己所需的内容,以及通过输出事件来通知外界操作。这种组件完全与业务逻辑解耦,因此它们不依赖于业务状态的变化,只专注于 UI 的展示。当业务逻辑发生变化时,不需要对它们做任何改动。

使用 Dumb components 有几个好处:

  1. 提高代码复用性:因为这些组件只负责渲染 UI,所以可以在多个地方重用。
  2. 易于测试:由于没有业务逻辑,只需测试组件的输入输出和渲染结果即可。
  3. 易于维护:每个组件功能单一,当 UI 或业务逻辑变化时只需修改与之相关的组件,降低了出错的概率。

下面是一个简单的例子,通过具体代码来说明什么是 Dumb components 以及如何使用。

例子:一个用户卡片组件

我们要实现一个用户卡片组件,它只负责展示用户信息,并提供一个按钮来触发"删除"操作。所有的用户数据和删除操作的业务逻辑都在父组件中管理。

Step 1: 创建 Dumb 组件

首先我们创建一个 UserCardComponent,它接受用户数据并展示,同时提供一个输出事件。

typescript 复制代码
// user-card.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-user-card',
  templateUrl: './user-card.component.html',
  styleUrls: ['./user-card.component.css']
})
export class UserCardComponent {
  @Input() user: any;
  @Output() delete = new EventEmitter<void>();

  onDelete() {
    this.delete.emit();
  }
}
html 复制代码
<!-- user-card.component.html -->
<div class="user-card">
  <h3>{{ user.name }}</h3>
  <p>{{ user.email }}</p>
  <button (click)="onDelete()">Delete</button>
</div>

这里 UserCardComponent 仅负责展示用户信息,并且提供了一个 onDelete 方法来触发 delete 事件。组件的输入属性 user 是一个对象,包含用户的 name 和 email 信息。

Step 2: 在父组件中使用 Dumb 组件

创建一个父组件 UserListComponent 来管理用户列表和删除操作。

typescript 复制代码
// user-list.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent {
  users = [
    { name: 'John Doe', email: 'john.doe@example.com' },
    { name: 'Jane Doe', email: 'jane.doe@example.com' }
  ];

  deleteUser(index: number) {
    this.users.splice(index, 1);
  }
}
html 复制代码
<!-- user-list.component.html -->
<div>
  <app-user-card
    *ngFor="let user of users; let i = index"
    [user]="user"
    (delete)="deleteUser(i)">
  </app-user-card>
</div>

在 UserListComponent 中,维护了一个用户数组 users。为了删除用户,我们定义了一个 deleteUser 方法,并在模板中通过 Angular 的 *ngFor 指令渲染多个 UserCardComponent。当 UserCardComponent 触发 delete 事件时,调用父组件的 deleteUser 方法进行相应处理。

Dumb 组件的进一步优化

为了更通用化和可维护,可以把输入数据的类型和输出事件的类型定义更加明确。

定义用户模型

typescript 复制代码
// user.model.ts
export interface User {
  name: string;
  email: string;
}

在组件中使用模型

typescript 复制代码
// user-card.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { User } from './user.model';

@Component({
  selector: 'app-user-card',
  templateUrl: './user-card.component.html',
  styleUrls: ['./user-card.component.css']
})
export class UserCardComponent {
  @Input() user: User;
  @Output() delete = new EventEmitter<void>();

  onDelete() {
    this.delete.emit();
  }
}

在父组件中使用模型

typescript 复制代码
// user-list.component.ts
import { Component } from '@angular/core';
import { User } from './user.model';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent {
  users: User[] = [
    { name: 'John Doe', email: 'john.doe@example.com' },
    { name: 'Jane Doe', email: 'jane.doe@example.com' }
  ];

  deleteUser(index: number) {
    this.users.splice(index, 1);
  }
}

通过这些步骤,我们实现了一个典型的 Dumb 组件。它只专注于展示用户信息,通过触发 delete 事件通知父组件,而父组件负责管理用户数据和删除操作的具体实现。

总结

Dumb components 是实现单一职责原则的关键,它们通过接收输入和发送输出事件,把业务逻辑和 UI 表现分离开来,提高了代码的复用性、可测试性和可维护性。通过上面的例子展示了在 Angular 中如何创建和使用 Dumb components,从而使应用程序更加模块化、结构清晰。

相关推荐
Profile排查笔记12 小时前
有哪些开源指纹浏览器项目?先核对客户端、内核与许可证
前端·人工智能·后端·自动化
CodeGL12 小时前
16、Python Web开发
开发语言·前端·python
FRing0313 小时前
JavaScript入门到精通二十九(内置构造函数(Object、Array))
开发语言·前端·javascript
AAA程序技术13 小时前
从 DOM 到屏幕:浏览器渲染管线六步拆解
前端·浏览器
zach13 小时前
useContext 深入讲解:组件透传、原理与最佳实践
前端
张一凡9313 小时前
AI 改完代码,人却不知道它改了什么:架构漂移才是真正的成本
前端·后端·agent
sycmancia13 小时前
Qml——Text元素
java·前端·html
DevChronosands_13 小时前
浅谈感受之 React 与 Vue 😒
前端
代码猎人13 小时前
前端怎么掌握模块化
前端
天才熊猫君13 小时前
前端队列,我是怎么从 `push + shift` 换成游标的
前端·javascript