我遇到了这样的代码。问题是在选择已经在缓存中的项目后进度条没有消失(当缓存内的 api 调用正常工作时)。我能够想出的是在点击执行操作后没有运行更改检测。有人可以向我解释为什么吗?
@Component({
selector: 'app-item',
templateUrl: `
<app-progress-bar
[isDisplayed]="isProgressBar"
></app-progress-bar>
<app-item-content
[item]="item$ | async"
></app-item-content>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ItemComponent {
@Input()
set currentItemId(currentItemId: string) {
if (currentItemId) {
this.isProgressBar = true;
this.item$ = this.cache.get(currentItemId).pipe(
tap(() => {
this.isProgressBar = false;
//adding this.changeDetector.detectChanges(); here makes it work
})
);
} else {
this.isProgressBar = false;
this.item$ = of(null);
}
}
item$: Observable<ItemDto>;
isProgressBar = false;
constructor(
private cache: Cache,
private changeDetector: ChangeDetectorRef
) {}
}
缓存正在存储项目
private _data: Map<string, BehaviorSubject<ItemDto>>;
并过滤掉初始的空发射
也在变化
<app-progress-bar
[isDisplayed]="isProgressBar"
></app-progress-bar>
至
<app-progress-bar
*ngIf="isProgressBar"
></app-progress-bar>
无需手动触发更改检测即可使其工作,为什么?
缓存:
export class Cache {
private data: Map<string, BehaviorSubject<ItemDto>>;
get(id: string): Observable<ItemDto> {
if (!this.data.has(id)) {
this.data.set(id, new BehaviorSubject<ItemDto>(null));
}
return this.data.get(id).asObservable().pipe(
tap(d => {
if (!d) {
this.load(id);
}
}),
filter(v => v !== null)
);
}
private load(id: string) {
this.api.get(id).take(1).subscribe(d => this.data.get(id).next(d));
}
编辑:
所以我想:tap 正在作为异步操作运行,这就是为什么在组件上已经运行更改检测之后执行它的原因。像这样的东西:
- this.isProgressBar = true;
- 变更检测运行
- 点击(this.isProgressBar = false;)
但我正在摆弄它并做了这样的事情:
templateUrl: `
<app-progress-bar
[isDisplayed]="isProgressBar$ | async"
></app-progress-bar>
<app-item-content
[item]="item$ | async"
></app-item-content>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ItemComponent {
@Input()
set currentItemId(currentItemId: string) {
if (currentItemId) {
this.itemService.setProgressBar(true);
this.item$ = this.cache.get(currentItemId).pipe(
tap(() => {
this.itemService.setProgressBar(false);
})
);
} else {
this.itemService.setProgressBar(false);
this.item$ = of(null);
}
}
item$: Observable<ItemDto>;
isProgressBar$ = this.itemService.isProgressBar$;
现在我不知道为什么在 tap() 中进行操作后更改检测没有在组件上运行,它与区域有关吗?
物品服务:
private progressBar = new Subject<boolean>();
setProgressBar(value: boolean) {
this.progressBar.next(value);
}
get isProgressBar$() {
return this.progressBar.asObservable();
}