跳转到主要内容

Angular不断发展,创建组件的方法也在不断发展。加入我的组件开发指南之旅

去Angular 17是一段漫长的旅程。在保持向后兼容性的同时,Angular团队正在不断发展框架。和许多其他人一样,我发现自己一直在思考使用什么以及何时使用它。在本文中,我将表达我对创建新组件时应该使用什么的想法。

Signals

信号从版本16开始就可用了,它们是应用程序上管理状态的必备工具。如果你还没有使用Signals,是时候开始使用了。最初,可能会有一个学习曲线,但它很简单,随着时间的推移,它会变得很自然。与OnPush变化检测相结合,它提供了精细调整的反应性、性能增益和令人愉快的开发体验。

Observables

如果我们有信号,为什么我们需要可观察性?请记住,信号处理同步反应性,而可观察性处理异步反应性,例如HTTP请求,同时为我们提供与这些值交互的工具(map、switchMap)。

ChangeDetection.OnPush

首先,对每一个进行简要说明:

默认值:Angular触发对浏览器事件、计时器、XHR和承诺的更改检测。然后,系统从上到下依次检查组件树中的每个组件。在大型系统中,这可能会导致性能问题。

OnPush:它禁用默认的更改检测。简而言之,该组件仅在少数特定情况下重新渲染:

  • 异步管道新值
  • 输入引用已更改(引用,而不是值,不变性)。
  • 源自组件或其中一个子级的事件。
  • 手动触发器

那么,仅仅通过阅读以上内容,你就已经知道了吗?正确的

始终使用ChangeDetection。OnPush,当与Signals结合时,您可以将组件性能提升到另一个级别。此外,当Angular完成完全无区域的实现时,您的应用程序离实现它又近了一步。

控制流程

@if (a > b) {
  {{a}} is greater than {{b}}
}

自V17以来,我们为Angular提供了新的控制流程。是的,它在开发者预览版中,但它感觉非常自然和强大,因为它和js语法完全一样。因此,你应该使用它。然而,我发现自己仍然经常使用旧的*ngIf指令。有时你只想隐藏一个<span>,我认为这仍然比写三行更容易。可用的块是@If、@for、@switch。

Inject() VS constructor()

这个决定可能具有挑战性。我目前使用inject(),了解这两种方法的优缺点,尽管详细的探索超出了本文的讨论范围。

在我的特定情况下,对inject()的偏好很大程度上是由于语法糖。它与其他框架中的约定更加无缝地一致。尽管遇到了一些开发人员(最初包括我自己)的抵制,但在代码可读性方面,这种转变还是有回报的。然而,需要注意的是,我们并没有完全从使用constructor()中解放出来。我非常依赖它,尤其是Signal effect(),因为它们需要在注入上下文中运行。我发现这是在这种情况下最直接的方法。

供参考的组件:

import {
  ChangeDetectionStrategy,
  Component,
  inject,
  signal,
} from '@angular/core';
import { MsalService } from '@azure/msal-angular';
import { UsersService } from 'src/app/api/users-services';
import { Observable } from 'rxjs';
import { AsyncPipe, DatePipe } from '@angular/common';

export interface UserDetail {
  id: string;
  key: string;
  timestamp: string;
}

@Component({
  selector: 'app-users-widget',
  template: `<div>
    @if ((detailsList$ | async); as userData){
    <div>
      @for(data of userData; track data.id){
      <div (click)="setDetails(data)">
        {{ data.id }}
      </div>
      }
    </div>
    } @if (openDetail(); as openDetail){
    <h2>User Details</h2>
    <p>{{ openDetail.id }}</p>
    <p>{{ openDetail.key }}</p>
    <p>{{ openDetail.timestamp | date : 'long' }}</p>
    }
  </div> `,
  standalone: true,
  imports: [DatePipe, AsyncPipe],
  changeDetection: ChangeDetectionStrategy.OnPush,
})

export class UsersWidgetComponent {
  usersService = inject(UsersService);
  //# for private modifier
  #authService = inject(MsalService);

  openDetail = signal<UserDetail | null>(null);
  detailsList$: Observable<Array<UserDetail>> = new Observable();
  
  //Using the constructor instead of the ng lifecycle
  constructor() {
    this.retrieveFlowHistoryData();
  }
  
  retrieveFlowHistoryData() {
    const { username } = this.#authService.instance.getAllAccounts()[0];
    this.detailsList$ = this.usersService.apiFlowsHistoryGet$Json({
      UserName: username,
    });
  }

  setDetails(detail: UserDetail) {
    this.openDetail.set(detail);
  }
}

包装

浏览不断发展的库和框架可能是一项具有挑战性的任务。我相信这篇文章已经为您提供了一些最新的Angular约定的见解。直到下一次!

TL;DR

✅ 独立

✅ 注射

✅ 控制流程

✅ 可观察的

✅ 变更检测。OnPush

✅ Typescript private#修饰符

✅✅ 信号

✅ ‘as’用于变量中的存储条件

 

文章链接