什么是 Angular Composable 概念

什么是 Angular Composable 概念_第1张图片

我们都知道 Lodash,它是一个在项目中重用无状态逻辑的库。那么,如果在 Angular 项目中我们有一个类似的工具包来重用有状态逻辑呢?

Composables 并不是一个新的概念,它是来自 Vue.js 的一个概念。我在这篇博客中使用的许多示例和想法直接来自 Vue.js Composables 文档。

在版本 16.0.0-next.0 中,Angular 团队引入了 Signals 的实现,Signals 是一种反应性的基本组件,可以在 Angular 中提供精细的反应性能力。随着这样的重大变化,还考虑到 Angular 团队在最新版本中引入的其他非常有用的功能,比如 inject 函数或 DestroyRef 的概念,不可避免地会出现新的模式。本文试图在 Angular 的上下文中探索这个模式。

在 Angular 自身中,我们已经看到了我们可以称之为“功能型服务(Functional Services)”的过渡。它始于版本 14.2.0 中功能型守卫(functional guards)和解析器(resolvers)的引入,继续于版本 15.0.0 中功能型拦截器(functional interceptors)的引入。但是什么是 Angular Composable,为什么以及如何在项目中使用它?

什么是 Angular Composable?

在 Angular 应用程序的上下文中,一个 composable 是一个使用 Signals API 封装有状态逻辑的函数。这些可组合函数可以在多个组件中重复使用,可以相互嵌套,并且可以帮助我们将组件的有状态逻辑组织成小型、灵活和简单的单元。

与我们创建 util 函数以在组件之间重用无状态逻辑的方式相同,我们创建 composable 以共享有状态逻辑。

但是让我们看看在 Angular 应用程序中如何编写一个 composable。在下面的示例中,我没有使用 Angular Signals RFC 中提议的 API。当此 API 的所有功能就位时(例如应用程序渲染生命周期钩子,基于 Signal 的查询),我们将能够以更好的方式编写这些可组合函数,并能够为它们提供更多功能。

让我们从一个非常简单的示例开始。

Mouse Tracker Example

使用 Signals 在 Angular Component 里实现 mouse tracking 功能:

@Component({
  standalone: true,
  template: ` {{ x() }} {{ y() }} `,
})
export class MouseTrackerComponent implements AfterViewInit, OnDestroy {
  // injectables
  document = inject(DOCUMENT);

  // state encapsulated and managed by the composable
  x = signal(0);
  y = signal(0);

  ngAfterViewInit() {
    document.addEventListener('mousemove', this.update.bind(this));
  }

  // a composable can update its managed state over time.
  update(event: MouseEvent) {
    this.x.update(() => event.pageX);
    this.y.update(() => event.pageY);
  }

  ngOnDestroy() {
    document.removeEventListener('mousemove', this.update.bind(this));
  }
}

可以对其重构,增加通用性:

// mouse-tracker.ts file
export function useMouse() {
  // injectables
  const document = inject(DOCUMENT);

  // state encapsulated and managed by the composable
  const x = signal(0);
  const y = signal(0);

  // a composable can update its managed state over time.
  function update(event: MouseEvent) {
    x.update(() => event.pageX);
    y.update(() => event.pageY);
  }

  document.addEventListener('mousemove', update);

  // lifecycle to teardown side effects.
  inject(DestroyRef).onDestroy(() =>
    document.removeEventListener('mousemove', update)
  );

  // expose managed state as return value
  return { x, y };
}

其他 Component 也可以重用了:

@Component({
  standalone: true,
  template: ` {{ mouse.x() }} {{ mouse.y() }} `,
})
export class MouseTrackerComponent {
  mouse = useMouse();
}

你可能感兴趣的:(什么是 Angular Composable 概念)