Angular 中的函数式编程:探索注入和资源

Angular 不断发展的生态系统正在转向更具**功能性和响应性的编程**范式。借助**信号**、**资源 API**和**注入函数**等工具,开发人员可以简化应用程序逻辑、减少样板代码并增强可重用性。

这篇博文探讨了 Angular 的现代功能如何帮助开发人员以干净、声明性和反应性的方式处理异步逻辑。

Angular 函数式特性的主要优点

  • 可重用依赖注入函数:inject 函数允许开发人员创建与 Angular 依赖注入系统无缝集成的独立函数。这将业务逻辑与组件和服务分离,使函数可在整个应用程序中重用。
  • 简化状态管理:自动处理加载、成功和错误状态。
  • 增强的反应能力:当依赖关系发生变化时自动更新数据。
  • 减少样板:专注于逻辑,而不是手动订阅或生命周期管理。
  • 提高可读性:声明性模板使 UI 状态转换变得易于理解。
  • 步骤 1:API 和数据模型

    在此示例中,我们将从 REST API 获取帖子。每篇帖子均具有以下结构:

    export interface Post {
      userId: number;
      id: number;
      title: "string;"
      body: string;
    }

    API 的基本 URL 通过 `InjectionToken` 提供:

    import { InjectionToken } from '@angular/core';
    
    export const API_BASE_URL = new InjectionToken('API_BASE_URL', {
      providedIn: 'root',
      factory: () => 'https://jsonplaceholder.typicode.com',
    });

    第 2 步:定义数据获取函数

    1. 传统的基于 RxJS 的方法

    以下函数使用 Angular 的 `HttpClient` 通过其 ID 获取帖子:

    import { HttpClient } from '@angular/common/http';
    import { inject } from '@angular/core';
    import { Observable } from 'rxjs';
    import { API_BASE_URL } from '../tokens/base-url.token';
    import { Post } from './post.model';
    
    export function getPostById(postId: number): Observable {
      const http = inject(HttpClient);
      const baseUrl = inject(API_BASE_URL);
    
      return http.get(`${baseUrl}/posts/${postId}`);
    }

    要在组件中使用此功能,您可以将其绑定到可观察对象并使用“异步”管道显示结果:

    import { AsyncPipe, JsonPipe } from '@angular/common';
    import { Component, signal } from '@angular/core';
    import { getPostById } from './shared/posts.inject';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [AsyncPipe, JsonPipe],
      template: `
        @if (post$ | async; as post) {
          

    {{ post | json }}

    } @else {

    Loading...

    } `, }) export class AppComponent { private readonly postId = signal(1); protected readonly post$ = getPostById(this.postId()); }

    限制

  • 反应性问题:信号变化(例如 postId)不会自动触发新的获取。
  • 手动错误处理:您必须为加载和错误状态编写自定义逻辑。
  • 2.基于信号的资源API方法

    Resource API 简化了响应性和状态管理。以下是使用 Resource API 的函数:

    import { inject, resource, ResourceRef, Signal } from '@angular/core';
    import { API_BASE_URL } from '../tokens/base-url.token';
    
    export function getPostByIdResource(postId: Signal): ResourceRef {
      const baseUrl = inject(API_BASE_URL);
      return resource({
        request: () => ({ id: postId() }),
        loader: async ({ request, abortSignal }) => {
          const response = await fetch(`${baseUrl}/posts/${request.id}`, {
            signal: abortSignal,
          });
          return response.json();
        },
      });
    }

    这种方法:

  • 当postId改变时自动重新加载数据。
  • 以声明方式处理加载、错误和成功状态。
  • 在组件中:

    import { JsonPipe } from '@angular/common';
    import { Component, signal } from '@angular/core';
    import { getPostByIdResource } from './shared/posts.inject';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [JsonPipe],
      template: `
        @if (post.isLoading()) {
          

    Loading...

    } @else if (post.error()) {

    Error: {{ post.error() }}

    } @else {

    {{ post.value() | json }}

    } `, }) export class AppComponent { private readonly postId = signal(1); protected readonly post = getPostByIdResource(this.postId); }

    资源 API 的主要功能

    声明式状态管理

    Resource API 会自动管理“正在加载”、“错误”和“成功”等状态。这样就无需自定义标志,并确保模板更清晰。

    反应性

    Resource API 与 Signals 紧密集成。对 Signal 的更改会自动触发加载器函数,确保您的 UI 始终反映最新数据。

    错误处理

    错误集中并通过`.error()`公开,简化了模板中的错误管理。

    自动生命周期管理

    当依赖项(例如 `postId`)发生变化时,API 会取消正在进行的请求,从而防止竞争条件和陈旧数据。

    RxJS 与 Resource API:快速比较

    结论

    Angular 的“inject”函数和基于信号的资源 API 代表了简化异步逻辑的一次飞跃。借助这些工具,开发人员可以:

  • 解耦业务逻辑与组件。
  • 编写可重用的函数,与 Angular 的依赖注入系统无缝集成。
  • 消除状态管理的样板。
  • 轻松构建反应性和声明性应用程序。
  • Resource API 尤其适合现代 Angular 项目,可提供自动响应和声明式状态处理。立即开始探索这些功能,将您的 Angular 开发提升到新的水平!