Jam*_*ing 1 angular async-pipe
我正在研究遗留的角度代码,原来的开发人员已经走了。我在模板中看到了很多异步管道。它会导致更多的变化检测吗?
模板:
<div>{{(cart$ | async)?.name}}</div>
<div>{{(cart$ | async)?.price}}</div>
<div>{{(cart$ | async)?.count}}</div>
Run Code Online (Sandbox Code Playgroud)
我应该重构代码,让父组件模板异步管道cart$并将其传递给子组件吗?我知道这样代码更干净,除此之外,还有其他优点吗?谢谢!
<child [cart]="cart$ | async"></child>
Run Code Online (Sandbox Code Playgroud)
对同一个可观察值多次使用是否会AsyncPipe导致额外的更改检测周期?不,不一定。当 observable 发出时,所有订阅者(每次使用一个订阅者AsyncPipe)都会标记该组件以进行更改检测,但是一旦标记了某个组件,它将在下一个周期中进行检查。在同一周期中再次将其标记为更改没有任何效果。
通过多个订阅会遇到的问题AsyncPipe是每个订阅都是潜在的 API 调用或副作用触发器。
对于简单的可观察量,这不是问题。data$在下面的示例中,我们进行多个订阅并不重要。
data$ = new BehaviorSubject<int>(0);
Run Code Online (Sandbox Code Playgroud)
<p>{{ data$ | async }}</p>
<p>{{ data$ | async }}</p>
<p>{{ data$ | async }}</p>
Run Code Online (Sandbox Code Playgroud)
即使是很小的变化也会导致这成为一个问题。考虑我们必须触发一些副作用的情况:
counter = 0;
data = new BehaviorSubject<int>(0);
data$ = this.data.pipe(
tap(() => console.log(++this.counter))
);
Run Code Online (Sandbox Code Playgroud)
<p>{{ data$ | async }}</p>
<p>{{ data$ | async }}</p>
<p>{{ data$ | async }}</p>
Run Code Online (Sandbox Code Playgroud)
我们期望每次data发出一个新值时,我们的模板都会更新,并且我们会看到计数器增加一。我们实际看到的是计数器增加了 1 三次。每个订阅都会重新触发 中的副作用tap。您可以想象,如果副作用代价高昂,如果副作用改变了临界状态,或者如果我们使用//switchMap从流中执行某些 API 调用,情况会变得多么糟糕。concatMapmergeMap
如果您确实只需要创建单个订阅,则可以通过以下两种方式之一执行此操作:ng-container或将订阅提取到父组件中。
如果孩子应该管理订阅,则可以将其留给孩子。您可以使用如下模式订阅一次并共享结果。
<ng-container *ngIf="data$ | async as data">
<p>{{ data }}</p>
<p>{{ data }}</p>
<p>{{ data }}</p>
</ng-container>
Run Code Online (Sandbox Code Playgroud)
如果子级仅仅是展示性的(它不知道数据来自哪里,不修改数据等),那么您可能应该将订阅提取到父级。您甚至可能希望设置子级的更改检测策略,以OnPush避免触发更改检测,除非父级提供新数据。
@Component({
selector: 'app-child',
template: `
<p>{{ data }}</p>
<p>{{ data }}</p>
<p>{{ data }}</p>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Input() data: int;
}
Run Code Online (Sandbox Code Playgroud)
@Component({
selector: 'app-parent',
template: `
<app-child [data]="data$ | async"></app-child>
`
})
export class ParentComponent {
counter = 0;
data = new BehaviorSubject<int>(0);
data$ = this.data.pipe(
tap(() => console.log(++this.counter))
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
923 次 |
| 最近记录: |