[译2024]Signal Input 现已在 Angular 开发者预览版中提供
在 Angular 17.1 中,我们引入了基于 Signal 的 Inputs,作为基于装饰器的 @Input() 的响应式替代方案。
新的 Signal Inputs 为开发人员提供了新的方法:
- 让您立即集成 Angular Signals 并从中受益:
- 提供更简单的方法来在 Inputs 发生变化时运行逻辑。
- 从 Inputs 派生状态的有效解决方案。
- 实现
OnPush和未来的 Zoneless 更流畅的体验。
- 通过提高 Inputs 的类型安全性来提高代码质量和开发人员的工作效率。
这些可在开发者预览版中使用,我们希望获得您的反馈!
什么是 Signal Inputs?
与 @Input 一样,Signal Inputs 允许从父组件绑定值。与 Signal Inputs 的一个关键区别是,这些值使用 Signal 公开,并且可以在组件的生命周期中更改。
现在,开发人员可以利用 Signals 的力量以反应方式有效地响应这些潜在的变化。 Angular 支持两种 Signal Inputs 变体。
- Optional inputs – 默认情况下 Inputs 是可选的。您可以指定显式的初始值,否则 Angular 将隐式使用 undefined 作为初始值。
- Required inputs – 必填的 Inputs 始终具有给定 Inputs 类型的值。不能有初始值,必填的 Inputs 使用
input.required函数声明。
每当您使用 input 或 input.required 函数作为类成员的初始值设定项时,Angular 都会自动识别 Inputs。下面演示了如何在应用程序中声明 Signal Inputs:
import { Component, input } from '@angular/core';
@Component({…})
export class MyComp {
// optional inputs
firstName = input<string>();
age = input(0);
// required inputs
lastName = input.required<string>();
}
定义它们后,您可以在模板中使用它们,其语法与其他 Signals 相同:
<p>First name: {{ firstName() }}</p>
<p>Last name: {{ lastName() }}</p>
请参阅Signal Inputs专用指南了解更多信息。 https://angular.io/guide/signal-inputs 。
为什么 Signal Inputs 更适合您的应用?
与基于装饰器的 @Input 相比,Signal Inputs 提供了许多好处:
- Signal Inputs 在模板中使用时,会自动将
OnPush组件标记为脏(dirty)。- 这提高了代码质量和开发人员体验 (DX),并为 Zoneless 铺平了道路。
- Signal Inputs 更加类型安全:
- 与今天不同,Required inputs 不需要初始值或其他技巧来满足 TypeScript。
- 对转换进行类型检查以匹配接受的输入值。
- 每当 Inputs 发生变化时,都可以使用
computed轻松地派生值,就像其他 Signals 一样。 - 使用
effect而不是ngOnChanges或 setters,更轻松、更本地地监视 Inputs。
Angular 团队建议,一旦 Signal Inputs 脱离开发者预览并在即将推出的版本中升级为生产就绪,就使用 Signal Inputs。
利用 Signals 的力量
Signals 提供了强大的反应性模型,使您能够有效地监视更改、派生值,同时在应用程序的特定部分需要重新渲染时自动通知 Angular。
这使得构建仅刷新实际更改的部分的高性能应用程序变得更加容易和安全。
下面我们重点介绍一些潜在的用例。
声明与渲染
此示例演示如何声明组件的 Signal Inputs 并显示其值。
import { Component, input } from '@angular/core';
@Component({
// …
template: `Your name is: {{ yourName() }}`,
})
class HelloComponent {
yourName = input.required<string>();
}
观察变化
此示例监视 firstName Input 的更改,并使用 effect() 对这些更改做出反应:
import { input, effect } from '@angular/core';
class MyComp {
firstName = input.required<string>();
constructor() {
effect(() => {
// will be called when `firstName` is initialized or changes.
console.log(this.firstName());
});
}
}
派生值
您可以使用 computed 根据 Signal Inputs 有效地派生值。Signal Inputs 可以像应用程序中的任何其他 Signals 一样在 computed 中使用。
在以下示例中,我们从名为 age 的 Input 中派生一个值。每当 age 发生变化时, ageMultiplied 字段都会收到通知,并且可以重新运行以将年龄乘以 2。另一方面,如果 age 没有改变,则 ageMultiplied 推导将有效地使用先前存储的值而不执行。
import {Component, input, computed} from '@angular/core';
@Component({…})
export class MyComp {
age = input(0);
// age multiplied by two.
ageMultiplied = computed(() => this.age() * 2);
}
值转换
Signal Inputs 支持与基于装饰器的 Inputs 相同的功能。您可以为 Signal Inputs 指定转换函数,以将原始值解析为您期望的 Inputs 类型。
请注意,值转换永远不应该改变 Inputs 的含义。有关这方面的更多信息,请参阅 angular.dev 的新指南 — https://angular.io/guide/signal-inputs#value-transforms
export class MyCheckboxComponent {
disabled = input(false, {
// supports `<my-checkbox disabled="" />` as a shorthand
transform: (v: boolean|string) => typeof v === 'string' ? v === '' : v,
});
}
别名
您还可以做一些事情,例如为 Inputs 添加别名以满足您的需求:
export class StudentDirective {
age = input(0, { alias: 'studentAge' });
}
仅仅是开始
我们非常高兴能够在开发者预览版中将此功能引入 Angular 社区。Signal Inputs 现在即可使用,并且已做好生产准备。开发者预览版允许我们根据从社区收到的反馈进行更改。
考虑到这一点,在我们继续稳定 Signal Inputs 的过程中,我们希望得到您的反馈。对于即将推出的 API,存在一些复杂的权衡和其他问题:
input<string>()的简写可能会令人困惑,因为 Inputs 隐式使用undefined作为初始值。- 这是否令人困惑,因为通用仅显示
string? - 我们相信简写是有用的,因为我们看到大多数 Inputs 都使用
undefined作为 Google 代码库中的初始值。
- 这是否令人困惑,因为通用仅显示
- Inputs 现在是只读的。
- 以前使用 @Input 时,您可以通过从组件内部更新来取消同步 Inputs。
- 这会影响你的应用程序吗?如果您打算更新 Inputs,请考虑使用
model()并向消费者公开组件的更新状态。为什么这对你不起作用?
您的反馈很有价值,我们期待您的来信。如果您有反馈意见,请考虑在 GitHub 或 X 上的评论中告知我们。
请务必立即使用 ng update 安装最新版本的 Angular 来尝试 Signal Inputs。
谢谢并让我们了解最新情况!
原文链接:https://blog.angular.dev/signal-inputs-available-in-developer-preview-6a7ff1941823
翻译链接:https://zhuanlan.zhihu.com/p/684098176