【问题标题】:ngOnChanges is calling up multiple timesngOnChanges 多次调用
【发布时间】:2019-12-16 04:29:20
【问题描述】:

我使用 ngFor 生成了多个离子幻灯片,并在其中插入了一个组件。它多次调用 ngOnChanges。我希望它只调用一次,以便我可以调用我的 api。

我尝试过使用多个角度生命周期钩子。

这就是我创建幻灯片的方式,菜单有 19 个元素

<ion-slides #slides [options]="slideOpts" (ionSlideDidChange)="slideChanged($event)">
<ion-slide *ngFor="let i of menu; let j = index">
  <h1>{{ i.name }}</h1>
  <app-homenews [categoryId]="currentCategoryId" ></app-homenews>
</ion-slide>
</ion-slides>

这就是我们进行变更检测的方式

@Input() categoryId: number;

ngOnChanges(changes: SimpleChanges) {
   let chg = changes['categoryId'];
   console.log(chg.currentValue);
} 

我希望它只被调用一次,它现在调用了 19 次。

我可以在这里使用 rxjs 吗?

【问题讨论】:

    标签: angular ionic-framework angular7 ionic4


    【解决方案1】:

    ngOnChanges 在输入变量的值发生变化时运行来自模板绑定。因此多次触发它是正常行为。如果您只想执行一些代码,您可以像这样使用它

    @Input() isFirstRun;
    ngOnChanges(changes: SimpleChanges) {
      if(this.isFirstRun){
         let chg = changes['categoryId'];
         console.log(chg.currentValue);
      }
    }
    
    <ion-slide *ngFor="let i of menu; let j = index">
      <h1>{{ i.name }}</h1>
      <app-homenews [isFirstRun]="j===0?true:false" [categoryId]="currentCategoryId" ></app-homenews>
    </ion-slide>
    

    【讨论】:

    • 我怀疑上述任何一项都不会起作用,因为组件模板在 for 循环内,因此它每次都会调用 ngOnInit(与调用 ngOnChanges 相同 - 即使 CurrentCategoryId 不会在循环内修改)由于同样的原因,变量方法也不起作用,该变量每次都会获得默认值
    • 因此您可以将isFirstRun 作为输入变量并从父级提供它。在模板第一次迭代中您可以将值发送为真。
    【解决方案2】:

    您可以在服务中添加 isFirstRun 标志并在您的组件中使用它 您可以继续使用 ngOnchanges,因为它会在值发生变化时有所帮助

    ngOnChanges(changes: SimpleChanges) {
    if (this.flagService.isFirstRun || value has changed) {
    // call API
    }
    } 
    

    【讨论】:

      【解决方案3】:

      我用过一次这个方法来避免使用 ngOnChanges 循环。

      在您的组件中:

      private _changes;
      private id;
      @Input()
        set changes(changes) {     
      
            this._changes= changes;
            this.id = changes[id];
      
          }
        }
        get changes(): string {
          return this._changes;
        }
      

      【讨论】:

        【解决方案4】:

        虽然其他答案在技术上是正确的,但我觉得最好使用已传递给生命周期挂钩的 getter-setter 或 SimpleChanges 对象,而不是 isFirstRun 标志。 SimpleChanges 对象包含您已经需要的所有信息。

        class SimpleChange {
          constructor(previousValue: any, currentValue: any, firstChange: boolean)
          previousValue: any
          currentValue: any
          firstChange: boolean
          isFirstChange(): boolean
        }
        

        在运行时,包含一个/多个 SimpleChanges 对象对应于组件的 Input 变量的对象将被传递到 NgOnChanges 中,具有上述格式。像我在下面所做的那样检查 firstChange 值会更容易;

        @Input() categoryId: number;
        
        ngOnChanges(changes: SimpleChanges) {
           if(changes['categoryId'].firstChange) {
             let chg = changes['categoryId'];
             console.log(chg.currentValue);
             //other program logic
           }
        } 
        

        请注意:如果您将来自 API 响应的数据输入到子组件中,则很可能在 API 调用运行之前初始化时会发送一个空值,并且该输入的 firstChange 将设置为 true。在这种特殊情况下,检查之前的值是否为 null 以及当前值是否存在就足够了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-01
          • 2019-11-15
          • 2020-10-08
          • 2023-02-22
          • 2018-09-17
          • 2016-12-30
          • 1970-01-01
          • 2017-08-16
          相关资源
          最近更新 更多