Reputation: 785
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
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
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