自 Angular 最新版本以来,在框架内开发了一种新的原始反应系统:信号!
今天,事后看来,我们意识到某些用例尚未被覆盖,显然 Angular 团队的积极反应将为我们提供帮助来覆盖这些用例。
这些用例是什么?将采取哪些解决方案以及如何使用它们?
让我们首先说明这个问题。
假设我们有一篮子一定数量的水果。
数量由输入水果的组件管理。
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
如果输入的水果价格发生变化,则必须重置变量。
一个简单的解决方案是使用效果
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = signal(1); countEffect(() => { this.fruit(); this.quantity.set(1); }, { allowSignalWrites: true }) updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
前面的代码是不好的做法。为什么这是一个大问题?
我们需要将 signalWrites 选项设置为 true 才能设置信号量。这是由于对给定问题的误解造成的。
在我们的例子中,我们想要同步两个变量,在我们的具体化中,这两个变量是不同步的
柜台并不独立于水果,水果是我们最初的来源。实际上,这里我们有一个组件状态,其初始来源是水果,其余部分是水果的衍生物。
具体化问题如下
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{fruitState().quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); fruitState = computed(() => ({ source: fruit(), quantity: signal(1), })); updateQuantity(): void { this.fruitState().quantity.update(prevCount => prevCount++); } }
这种具体化将水果与其数量紧密联系起来。
因此,一旦水果发生变化,计算变量fruitState就会自动重新计算。此重新计算返回一个具有数量属性的对象,该对象是一个初始化为 1 的信号。
通过返回信号,变量可以在点击时递增,并在水果变化时简单地重置。
这是一个相对简单的设置模式,但我们不能简化它吗?
随着 Angular 19 的到来,一个用于计算派生信号的新函数。
到目前为止,我们已经有了计算函数,但该函数返回一个 Signal 而不是 WrittableSignal,这在我们之前的数量变量用例中是实用的。
这就是 LinkedSignal 的用武之地。LinkedSignal,顾名思义,允许您将两个信号强链接在一起。
如果我们回到之前的情况,这个函数将允许我们简化代码,如下所示:
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = linkedSignal({ source: fruit, computation: () => 1 }); updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
linkedSignal函数定义如下:
linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>; linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
在第一个定义(“缩写”定义)中,linkedSignal 函数采用计算函数作为参数和配置对象。
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
在前面的示例中,由于计算函数取决于数量信号,因此当数量变化时,计算函数会重新评估。
在第二个定义中,linkedFunction方法将一个对象作为具有三个属性的参数
与“缩写”计算函数相反,这里的计算函数将源值和“先例”作为参数。
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = signal(1); countEffect(() => { this.fruit(); this.quantity.set(1); }, { allowSignalWrites: true }) updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Angular 19 将引入一个新的 API,用于简单的数据获取和查询状态(待处理等)、数据和错误的检索。
对于那些稍微熟悉框架的人来说,这个新 API 的工作方式有点像 useRessource 钩子。
让我们看一个例子:
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{fruitState().quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); fruitState = computed(() => ({ source: fruit(), quantity: signal(1), })); updateQuantity(): void { this.fruitState().quantity.update(prevCount => prevCount++); } }
关于此代码片段,有几件事需要了解
这段代码中有几点需要注意:
以下效果将打印这些值
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = linkedSignal({ source: fruit, computation: () => 1 }); updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
如上所述,默认情况下,fruitId 信号是未跟踪的。
那么每次这个信号的值发生变化时如何重新启动http请求,以及如果fruitId信号的值发生变化而对上一个请求的响应没有变化,如何取消上一个请求到了吗?
资源函数采用另一个名为 request 的属性。
此属性将依赖于信号的函数作为其值并返回其值。
linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>; linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
如上面的代码所示,加载器函数有两个参数
因此,如果在 httpRequest 检索水果详细信息期间,fruitId 信号的值发生变化,则该请求将被取消以启动新请求。
最后,Angular 还想到了将这个新 api 与 RxJs 耦合的可能性,让我们能够从 Rx 运算符的强大功能中受益。
互通性是通过 rxResource 函数实现的,它的定义方式与资源函数完全相同。
唯一的区别是 loader 属性的返回类型,它将返回一个 observable
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
这里不需要abortSignal,当信号fruitId的值改变时取消之前的请求,隐含在函数rxResource中,行为与switchMap操作符相同。
以上是Angular 反应性的下一个改进的详细内容。更多信息请关注PHP中文网其他相关文章!