gpt4 book ai didi

Angular 异步管道未触发 NgOnChange 的更改检测

转载 作者:行者123 更新时间:2023-12-04 15:51:26 30 4
gpt4 key购买 nike

我遇到过这样的代码。问题是在选择已经在缓存中的项目后进度条没有消失(当缓存中的 api 调用使其工作正常时)。我能想到的是在 tap 中执行操作后没有运行变化检测。有人可以向我解释为什么吗?

@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>>;并过滤掉初始的 null emit

也在变化

<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 正在作为异步操作运行,这就是为什么它在更改检测已经在组件上运行后执行的原因。像这样:

  1. this.isProgressBar = true;
  2. 变化检测运行
  3. 点击(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();
}

最佳答案

对我来说,您的代码有两个主要问题:

  • 您的缓存可能不会发出新值(我不知道是因为您没有提供它的实现),这意味着 async 管道不会被触发,

  • 因为您检测到 onPush,所以您的 View 没有被任何东西刷新:只有您触摸的方法/属性正在更新。 item$ 与您的进度条无关,除非您使用 detectChanges(它会触发组件更改检测),否则您看不到它正在更新。

关于 Angular 异步管道未触发 NgOnChange 的更改检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53665767/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com