Yaroslav Draha
Yaroslav Draha

Reputation: 785

Angular 2 Redux constantly re-rendering in NgFor

I use NGRX in my project, and have problem with constantly re-rendering of components. The Store produces every time completely new object, if the store data the same, i dont want to re-render my component. I changed change detection of presentation components to ChangeDetectionStrategy.OnPush lodash memoization (_.memoization), but it not works

State of store

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

Then map Store state to structure as this

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

And trying to prevent re-rendering of cardsB items every time when store changing by memoize from lodash

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

In my Smart Component i have next html

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

To the my surprise it correctly works with one ngFor, but if i have two ngFor it is not works!

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

I have already spended 2 days for it, and it is killing me, please, help!

I am not native English speaker, sorry for mistakes.

Thanks!

Upvotes: 0

Views: 1465

Answers (2)

matmo
matmo

Reputation: 1379

If you have:

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

Then if outer changes at some point, the inner ngFor will re-render, which is why you see the alerts from ngOnInit. But if you add a trackBy to your outer ngFor, and it recognizes it as the same element, then you can avoid the inner list re-rendering, which is your current problem.

The inner trackBy only preserves the inner elements and prevents those from being re-created. The outer trackBy preserves the outer elements, which allows the inner elements the chance to be preserved too.

Upvotes: 1

CharanRoot
CharanRoot

Reputation: 6325

Use trackBy in the For loop. It will keep track of State and when ever data is changed than it will trigger re render.

    <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
  }

read below doc you will understand more. https://v2.angular.io/docs/ts/latest/api/common/index/NgFor-directive.html

Upvotes: 1

Related Questions