首页 > 解决方案 > 父组件的角度无限重新渲染

问题描述

Stackblitz 重现问题

您好,我的 Angular7 应用程序由一个名为 的父组件timesheet和一个名为 的子组件组成row。在这个例子中,我想timesheet生成一个<app-row>为给定月份的每一天

现在,<app-row>组件只包含一个带有接受数字的字段的<td>元素。input到目前为止没有什么太花哨的。

时间表组件:

<div *ngFor="let week of splitMonthIntoWeeks(getMonthDays(month))">
  <table>
    <thead>
      <tr>
        <th>
          Hours:
        </th>
      </tr>
    </thead>
    <tbody>
      <tr app-row *ngFor="let day of week"></tr>
    </tbody>
  </table>
</div>

行组件:

<td><input type="number"></td>

这工作得很好。但是,如果我尝试使用[(ngModel)]指令将每个行组件的输入元素链接到模型中的属性,我会无限次重新呈现应用程序(您可以在上面的链接中重现。起初它会正常工作,你必须添加[(ngModel)]指令添加到行组件,如下所示)。

总而言之,这种变化提供了无限的重新渲染:

<td><input type="number" [(ngModel)]="hours"></td>

现在,我真的不知道 Angular 如何管理更改,也许我遗漏了一些东西,所以任何提示都将不胜感激。

标签: javascriptangular

解决方案


在此处查看解决方案

https://stackblitz.com/edit/angular-cjxqyt

你不应该直接在模板中调用你的函数(splitMonthIntoWeeksgetMonthDays),因为它会在每个渲染周期被调用。Date这意味着对于每次调用,都会生成一个包含 new 的新数组。ngFor通过检查其值是否与===上一个循环严格相同的对象(带有 )来工作。

如果比较不匹配,ngFor则认为它是一个新对象,因此它会销毁相应的 DOM 元素并生成一个新对象。您可以console.logRowComponent组件构造函数中看到它。

在比较两个复杂对象时,就像Date它检查对象是否真的相同(内存中的指针相同),但在您的情况下,这不是因为函数不断重新创建新对象。

因此,您可以创建数组并将结果保存在本地属性中,并仅在@Input month更改时重新计算此数组,而不是在每个周期中调用您的函数。为此,您可以使用onChanges生命周期,或为您使用 setter @Input(如我的示例中)。


推荐阅读