NgOnInit似乎在Input()接收数据之前被触发

时间:2020-09-17 13:22:16

标签: angular typescript input rxjs ngrx

作为个人挑战,我正在尝试创建一个网站,在该网站中您可以看到英雄联盟冠军名单,然后单击他们的图标以获取更多详细信息。

但是,我的冠军的详细信息(特别是图片)似乎延迟了一秒钟。

Here, I clicked on the image of Kaisa, but the image of the previous champ is displaying 在这里,我点击了Kaisa的图片,但是上一个冠军的图片正在显示

这是我获取数据的方式。

家长TS

export class ChampionListComponent implements OnInit {

  public displayPopup = false;
  public selectedChamp: Observable<any>;
  constructor(private store: Store<LolState>) { }

  ngOnInit() {
    this.selectedChamp = this.store.pipe(select(selectChampDetails));
  }

  selectChamp(name) {
    this.displayPopup = true;
    this.store.dispatch(new GetChampionsDetails(name));
  }

PARENT HTML

<ul class="champion_list">
  <li (click)="selectChamp(champion.key)">
    ...List of champions
  </li>
</ul>

<ng-container *ngIf="displayPopup">
  <app-champion-details *ngIf="selectedChamp | async as champ" [selectedChamp]="champ"></app-champion-details>
</ng-container>

儿童TS

export class ChampionDetailsComponent implements OnInit {

  @Input() selectedChamp: any;
  public skins: Array<{path: string}>;
  constructor() { }

  ngOnInit(): void {
    if (this.selectedChamp.skins) {
      this.skins = this.selectedChamp.skins.map(skin => {
        return {path: 'LINK'}
      })
    }
  }

儿童HTML

<section *ngIf="selectedChamp as Champ" class="container">
    <carousel cellWidth="100%" cellToShow="1" [loop]="true" [images]="skins"></carousel>
    <div class="champ_infos">
        <h2>{{Champ.id | titlecase}}</h2>
        <h3>{{Champ.title | titlecase}}</h3>
        <article>
            {{Champ.lore}}
        </article>
    </div>
</section>

我从服务中获取信息,其中一个效果调用了该效果,该操作调度操作并以我的状态存储数据。信息以我的状态很好地存储,如果我尝试在父级中使用console.log selectChamp,它将显示良好的信息,在这里没有问题。

似乎Angular在输入接收到信息之前试图执行map吗?

编辑:我在孩子中将*ngIf="selectedChamp as Champ"替换为*ngIf="skins",因此除非全部加载,否则内容不会显示,您可以在gif中看到结果。

enter image description here

(我删除了一些与问题无关的代码,如果存在一些错别字/未知变量,请忽略它,因为这不是问题的根源)

3 个答案:

答案 0 :(得分:1)

将输入用于子组件时,该值在OnChanges生命周期中可用。 因此,您可以尝试以下方法:

ngOnChanges(changes: SimpleChanges) {
if(changes && this.selectedChamp && this.selectedChamp.skins){
  this.skins = this.selectedChamp.skins.map(skin => {
        return {path: 'LINK'}
      })
    }
 }

在此生命周期中,每次在父级中更新值时,您都可以在子级中获取它。

答案 1 :(得分:1)

问题是这样的:

<ng-container *ngIf="displayPopup">
  <app-champion-details *ngIf="selectedChamp | async as champ" [selectedChamp]="champ"></app-champion-details>
</ng-container>

displayPopup变为true时,您已经在显示champion-details,因为selectedChamp的Observable已经具有一个值,如果这是您第二次打开详细信息组件,则该值已经出现。新值将在稍后的时间异步到达,但是组件已经初始化,因此子组件的ngOnInit已实现,并且显示旧状态。

我建议您采取一些不同的方法。关闭明细组件时,请清除商店中的selectedChamp。这样一来,您甚至都不需要ng-container,而只需依靠*ngIf="selectedChamp | async as champ"来显示详细信息部分。

  <app-champion-details *ngIf="selectedChamp | async as champ" [selectedChamp]="champ"></app-champion-details>

因此,您可以在closeChampionDetails方法中执行以下操作:

public closeChampionDetails() {
  this.store.dispatch(new ClearSelectedChampion());
}

答案 2 :(得分:0)

在子组件中,必须防止在将输入selectedChamp传递给数据之前调用它,以便您可以执行类似的操作

ngOnInit(): void {
    if (this.selectedChamp && this.selectedChamp.skins) {
      this.skins = this.selectedChamp.skins.map(skin => {
        return {path: 'LINK'}
      })
    }
}