【问题标题】:Angular 2 Redux constantly re-rendering in NgForAngular 2 Redux 不断在 NgFor 中重新渲染
【发布时间】:2017-11-18 02:37:07
【问题描述】:

我在我的项目中使用 NGRX,并且在不断地重新渲染组件时遇到问题。 商店每次都会产生全新的对象,如果商店数据相同,我不想重新渲染我的组件。我将演示组件的更改检测更改为 ChangeDetectionStrategy.OnPush lodash memoization (_.memoization),但它不起作用

商店状态

export interface CardsState {
    cardsA: CardA[];
    cardsB: CardB[];
    cardsC: CardC[];
}

然后将 Store 状态映射为这样的结构

const entities = [{
 cards: {
  cardsB: [
   {}
  ]
 }
}];

并试图防止每次通过来自 lodash 的 memoize 更改存储时重新渲染 cardsB 项目

export const memoizeCardBFunc = _.memoize((cardB: CardB): CardB => {
  return _.cloneDeep(cardB);
}, (cardB: CardB) => cardB.entityType + cardB.entityId);

在我的智能组件中,我有下一个 html

<div *ngFor="let entity of entities | async">
    <div *ngFor="let cardB of entity.cards.cardsB">
        <card-b [cardStateModel]="cardB"></card-b>
    </div>
</div>

令我惊讶的是,它可以与一个 ngFor 一起正常工作,但如果我有两个 ngFor,它就不起作用了!

<div *ngFor="let cardB of entity.cards.cardsB">
    <card-b [cardStateModel]="cardB"></card-b>
</div>

我已经花了 2 天的时间,它正在杀死我,请帮助!

我的母语不是英语,如有错误,请见谅。

谢谢!

【问题讨论】:

  • 我不确定您为什么或如何使用 _.memoize 和 _.cloneDeep,但这听起来像是您在减速器中做错了什么。如果您的商店数据保持不变,则不应首先返回新对象。
  • @matmo @Jonnysai 这是我的问题plnkr.co/edit/gbjdubPeZQXo7j6L3E6w?p=preview 的一个笨蛋。 In 不适用于内部 ngFor。您可以删除第一个 ngFor 和第二个更改为 *ngFor="let cardB of entities[0].cards.cardsB; trackBy: trackByB" 并且它可以工作。我需要内在的 ngFor (
  • 似乎你需要在外部 ngFor 上添加 trackBy
  • @matmo 我不知道为什么,但它适用于外部 trackBy。您能否将此添加为答案,而不是我可以将您的答案标记为解决方案?

标签: angular memoization ngrx ngrx-store


【解决方案1】:

在 For 循环中使用 trackBy。它会跟踪状态,当数据发生变化时,它会触发重新渲染。

    <div *ngFor="let cardB of entity.cards.cardsB;let i = index; trackBy: trackByFn">
        <card-b [cardStateModel]="cardB"></card-b>
    </div>

trackByFn(index, item) {
    return index; // or item.id
  }

阅读下面的文档,您会了解更多。 https://v2.angular.io/docs/ts/latest/api/common/index/NgFor-directive.html

【讨论】:

  • 感谢您的回答!当我只有一个像这样*ngFor="let cardB of entities[0].cards.cardsB; 的 ngFor 时,这项工作很好,但它不适用于内部 ngFor
  • 使用另一个 trackBy 进行内循环。
  • 我在 trackByFn 中使用我的记忆功能 return item.entityId + item.entityType;} 中的密钥
【解决方案2】:

如果你有:

<div *ngFor="let outer of outers">
    <div *ngFor="let inner of outer.inners">
       {{ inner }}
    </div>
</div>

然后,如果outer 在某个时刻发生变化,内部 ngFor 将重新渲染,这就是为什么您会看到来自 ngOnInit 的警报。但是,如果您将 trackBy 添加到外部 ngFor,并且它会将其识别为相同的元素,那么您可以避免内部列表重新渲染,这是您当前的问题。

内部 trackBy 仅保留内部元素并防止重新创建这些元素。外层 trackBy 保留了外层元素,这使得内层元素也有机会被保留。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-18
    • 2017-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    相关资源
    最近更新 更多