操作员手册:从 v17.3 到 v21 的 Angular Signals 导航

发布: (2026年1月5日 GMT+8 05:02)
14 min read
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容,我将按照要求将其译成简体中文并保留原有的格式、Markdown 语法以及技术术语。谢谢!

Version 1.0

SectionTitle
1.1基于 Signal 的组件:完整工具箱
1.2使用 output() 和 RxJS 互操作
2.1从预览到正式:升级到稳定版
2.2Signal 驱动的服务模式
2.3实现无 Zone 的未来
3.1引入 Signal 表单:范式转变
3.2高级操作:异步数据与关联状态
4.1Signal‑基代码的核心原则
4.2升级你的系统:迁移路径
4.3迁移清单:一步步指南
4.4采用 signal 组件 – 用直接的 signal 调用替代 async pipe
4.5将服务从 BehaviorSubject 重构为 signal
Conclusion结论:Angular 响应式的新纪元
References

Introduction

欢迎,操作员。您已经获得了一台经历了深刻变革的机器的钥匙。最初在 Angular 中作为全新响应式原语出现的技术,已演变为一个完整集成的系统,重新定义了我们构建、管理和思考应用状态的方式。本手册将指导您掌握 Angular Signals 的演进——从 v17.3 中的基础 API 到 v21 的实验前沿。准备好重新校准您对响应式的理解吧。

1️⃣ Angular 17.3 – 第一个完整去装饰器的发布

Angular 17.3 提供了创建完全无装饰器、基于信号的组件的最后一块拼图。

  • 在 17.3 之前,Angular 已经提供了基于信号的 inputsinput())和 queriesviewChild())替代方案。
  • 组件 outputs 仍然依赖传统的 @Output() 装饰器和 EventEmitter

1.1 output() – 新的原语

Angular 17.3 引入了 output() 函数,使开发者能够编写所有 面向公共 API——inputs、outputs 和 queries——都以函数形式定义的组件。这创造了一致的、无装饰器的体验,并在概念上与其他基于信号的 API 对齐。

// Before: Angular ();

onClick() {
  this.clicked.emit();
}

// After: Angular 17.3+
import { Component, output } from '@angular/core';

@Component({ /* … */ })
export class SignalButtonComponent {
  clicked = output();

  onClick() {
    this.clicked.emit();
  }
}

output() 提供了一种轻量级、独立于 RxJS 的事件发射方式。虽然 EventEmitter 继承自 RxJS 的 Subject,但 output() 返回的新的 OutputEmitterRef 是一个更简洁、专用的原语。

2️⃣ RxJS Interop

Angular 团队提供了一个桥接,帮助在庞大的基于 RxJS 的代码生态中使用 @angular/core/rxjs-interop 包,该包现在包括:

实用工具目的
outputFromObservable()将 RxJS 流转换为组件输出
outputToObservable()将组件输出转换回 RxJS Observable

这些实用工具实现了 平滑、增量的迁移,无需对现有的响应式逻辑进行全面重写。

3️⃣ Angular 18 – 20 – 加固信号与新架构模式

Angular 18 到 20 期间的重点是 稳定信号 API 并建立新的架构模式。

  • 稳定的原语input()model()(双向绑定)以及基于信号的查询(viewChild()contentChildren())从开发者预览升级为稳定版。
  • v20 里程碑:所有基础响应式原语均被视为稳定,为企业长期采用信号提供了信心。

3.1 Signal‑In‑A‑Service 模式

不再在服务中使用 BehaviorSubject,开发者现在采用 signal‑in‑a‑service 方法:

import { Injectable, signal, computed } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class ItemService {
  // 私有、可写的 signal
  private _items = signal([]);

  // 公有、只读的 signal
  readonly items = this._items.asReadonly();

  // 用于派生状态的计算 signal
  readonly total = computed(() => this._items().length);

  // 公有方法用于变更状态
  addItem(item: string) {
    this._items.update(items => [...items, item]);
  }
}

好处

  • 干净的 单向数据流 —— 服务是唯一的真相来源。
  • 消费者在 不变更 底层数据的情况下响应状态变化。
  • 信号的同步特性提升 可测试性,并消除与 RxJS subjects 与订阅相关的样板代码。

3.2 无 Zone 的未来

传统 Angular 依赖 Zone.js 在任何异步操作后触发变更检测。虽然便利,但可能效率不高。

  • 信号提供细粒度的依赖图 —— Angular 能精确知道哪些组件/计算值依赖于被修改的信号,只更新这些部分。
  • 无 Zone 模式Angular v20.2 中成为稳定版,并在 Angular v21 中设为 默认

优势

  • 更小的 bundle 大小。
  • 更佳的运行时性能。
  • 更可预测的应用行为。

Demo: https://github.com/leolanese/Angular-Zoneless-Signals

4️⃣ Angular 21 – 下一代进化

在核心原语稳定的情况下,Angular 21 探索了一个 基于信号的丰富生态系统,旨在解决复杂的 Web 开发挑战(例如,信号表单、异步数据处理、关联状态)。这些工具将信号范式扩展到超越简单状态管理,使开发者能够使用统一的响应式模型构建 高性能、易维护的应用程序

5️⃣ 迁移检查清单 – 步骤指南

✅ StepAction
1在所有组件中将 @Input() 替换为 input()
2@Output() 替换为 output()
3将基于 EventEmitter 的输出转换为 output(),并在需要 RxJS 互操作时使用 outputFromObservable() / outputToObservable()
4重构服务:将 BehaviorSubject/ReplaySubject 替换为 私有可写信号 (signal()) 并公开 只读/计算信号
5更新模板:将 async 管道替换为直接信号调用 ({{ mySignal() }})。
6启用 无区模式 (enableProdMode(); setZoneEnabled(false);) 并测试变更检测行为。
7运行 Angular 迁移脚本 (ng update @angular/core@21)。
8验证单元和集成测试;调整所有依赖 RxJS 订阅副作用的测试。
9审查性能指标;确保包体积缩小和持续交付周期改进。
10为团队记录新模式并更新入职材料。

结论

Signals 已经将 Angular 从一个 zone‑centric、RxJS‑heavy 框架 转变为一个 fine‑grained、declarative 且 performant 平台。通过拥抱基于信号的 API,采用 signal‑in‑a‑service 模式,并启用 zoneless mode,您可以为您的应用程序在下一代 Web 开发中奠定基础。

References

Source:

Angular 中的 Signals – 未来一瞥

实验性的 signals 提供了一个预览,展示了一个将响应式无缝集成到框架每个部分的未来。

新的 Signal Forms API(Angular 21)

可通过 @angular/forms/signals 实验性使用。

Signal Forms 颠覆了传统思路:不再先构建与数据匹配的表单结构,而是从数据模型出发,让表单以响应式方式自行衍生。

模型优先(Model‑First)方式

// 将数据模型定义为 signal
user = signal({ firstName: '', email: '' });

// 根据模型创建表单
profileForm = form(this.user, (path) => [
  // …验证规则
]);

声明式验证

验证规则在表单的 schema 中以函数形式定义:

  • 内置验证器(requiredminLengthemail
  • 条件验证(when 属性)
  • 跨字段验证

这取代了传统表单中添加/移除验证器的命令式逻辑。

简化的模板绑定

旧的 formControlName 被全新的 [field] 指令 取代,在模板与表单字段 signal 之间建立直接、类型安全的链接。

内置提交处理

submit() 管理提交过程,自动处理加载状态(submitting())和服务器端错误,并可直接映射回表单字段。

结果: 大幅减少样板代码,提升类型安全性,验证逻辑更直观、易于维护。

其他实验性基于 Signal 的工具

工具描述
Resource API (resource, rxResource)声明式异步数据获取。当依赖的 signals(例如 params)变化时,资源会重新获取,并提供用于加载、错误和数值状态的内置 signals。
linkedSignal()一种高级原语,可写(不同于只读的 computed())。它从源 signal 派生初始值,但也可以手动更新——适用于例如下拉列表在选项变化时重置,但仍允许手动选择的场景。

Source:

第 4 章 – 操作员实用指南:最佳实践与迁移

掌握新系统需要了解其交互规则。本章提供关键原则和升级现有机器的战略计划。遵循这些最佳实践可让基于 signal 的应用保持 高性能可预测易维护

核心规则

  • 使用 computed() 处理派生状态 – 最重要的规则。如果一个值是由一个或多个 signal 计算得出的,始终使用 computed()。避免使用 effect() 去设置另一个 signal(这是一种会导致性能问题和意外行为的反模式)。
  • 仅在副作用时使用 effect() – 用于桥接非 signal 世界(例如日志记录、同步到 localStorage、自定义 DOM 操作)。请记住,effect 是异步执行的。
  • 保持状态扁平化 – 避免在 signal 中嵌套其他 signal 或深层对象。扁平化的状态结构更易追踪,也能实现更高效的变更检测。

4.2 升级机器与迁移路径

生成迁移示意图

# 将 @Input() 迁移为 signal 输入
ng generate @angular/core:signal-input-migration

# 将 @Output() 迁移为 signal 输出
ng generate @angular/core:signal-output-migration

# 将 @ViewChild/@ContentChild 查询迁移
ng generate @angular/core:signal-queries-migration

采用实验性的 Signal Forms API

  1. 确定要迁移的传统响应式表单。

  2. 为数据模型定义一个 signal:

    user = signal({ name: '', email: '' });
  3. 创建 signal 表单:

    profileForm = form(this.user, /* schema */);
  4. 更新模板 – 用 [field] 指令替换 formControlName

  5. form() 函数内部的声明式规则取代命令式验证。

Angular 17.3 新特性 – 作者 Gergely Szerovay

  • 新的 output() API
  • RxJS 互操作帮助函数(outputFromObservable, outputToObservable
  • HostAttributeToken
  • 支持 TypeScript 5.4

基于 Signal 的 Angular 架构:构建更智能的购物车

一本实用指南,介绍如何使用 “signal‑in‑a‑service” 模式重构状态繁重的功能,以实现更简洁、更易测试且性能更佳的应用。

基于 Signal 的 Angular 表单:它们将彻底改变你对表单处理的认知

提前了解 Angular 21 中实验性的 Signal Forms API,重点展示其 模型优先设计声明式验证类型安全的模板绑定

资源

  • Reactive Angular: Loading Data with the Resource API – 介绍实验性的 resourcehttpResource 原语,用于管理带有内置加载、错误和值状态信号的异步数据流。
  • Dependent state with linkedSignal – Angular Official Guide – 关于 linkedSignal() 的文档,它是可写的类似计算的信号,在其源变化时会重置——非常适合级联下拉框等动态 UI 控件。
  • Angular Signals Effect(): Why 90% of Developers Use It Wrong – 阐明了 effect() 的常见反模式,并强调它应仅用于副作用(例如日志记录、localStorage、DOM 变更)。
  • Angular Roadmap – Official angular.dev – Angular 战略优先级的权威来源,包含关于 Signals、无区块(zoneless)Angular、Signal Forms、HMR、测试工具以及未来探索的状态更新。
  • Meet Angular’s new output() API – Angular Blog – Angular 17.3 中 output() 函数的官方公告,解释了其类型安全、与信号输入的对齐,以及通过 outputFromObservable()outputToObservable() 与 RxJS 的互操作。
  • Angular v21 Goes Zoneless by Default: What Changes, Why It’s Faster, and How To – 对 Angular v21 默认采用无区块(zoneless)变更检测的深入分析——涵盖性能提升、包体积缩小、迁移步骤以及注意事项。

让我们保持联系!

Back to Blog

相关文章

阅读更多 »

Angular 21 — 新功能与变更

Angular 21 专注于简化、性能和现代响应式模式。它不是添加花哨的 API,而是强化 Angular 开发者已经使用的……

依赖跟踪基础(I)

什么是 Dependency Tracking?Dependency Tracking 是一种用于自动收集和记录数据片段之间关系的技术。它允许系统…

Anguar 小技巧 #4

介绍 一些关于使用 Angular 的技巧——来自前端开发者 第四部分。这些技巧假设你已经具备 Angular 经验,所以我们不会深入……

前端开发:每个网站的面孔

封面图片:前端开发:每个网站的面孔 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/htt...