2

I have a large array that I am using in a component (component A) with *ngFor with a nested *ngFor.

Component B initialises a jquery plugin which registers a document mousemove event handler, I am using this.zone.runOutsideAngular to init the plugin and I am calling this.ref.detectChanges() in the callback as I need to update the UI on mousemove inside the component B.

Component A is not a child of component B.

As soon as the component A is rendered change detection becomes very slow. the array does not change and I am using the ChangeDetectionStrategy.OnPush strategy for component A but when I fire ref.detectChanges() inside component B, ngDoCheck gets called on component A and I can see a noticeable jank on mousemove.

Is there a way to tell angular to completely ignore the large array of items in component A and allow me to handle when the UI should be updated? I thought that using ChangeDetectionStrategy.OnPush would give me what I need but I have tried removing all @Input()s from component A and anytime I call this.ref.detectChanges() inside component B it is still firing ngDoCheck and it is obvious that this is very slow.

I can scroll through the list of items no issue, but it is when I am triggering the detectChanges inside the mousemove on component B that is causing the issue. I know I could manually update the DOM but I think this would just be a workaround as it would only address the jank on mousemove and not the issue around the change detection being slow.

lin
  • 17,956
  • 4
  • 59
  • 83
raygerrard
  • 812
  • 11
  • 13
  • use 'trackBy : yourTrackByFn' in *ngFor . This will solve your issue, as whenever ChangeDetection happend it execute life cycle event for that component every time which impact on performance. – Amol Bhor Mar 23 '18 at 14:53

2 Answers2

2

I have got to the bottom of this issue.

The problem was that inside component A for the nested *ngFor I was using a child component to render each sub item which meant that although I was using the ChangeDetectionStrategy.OnPush strategy, it still required a ref check for each item.

I have now moved the html from the child component into component A directly and this has had a huge impact on performance.

raygerrard
  • 812
  • 11
  • 13
1

this.ref.detach() to remove the detector from from the tree completely, that should stop the checking. Then you can still call detectChanges to do it manually, and reattach to bring it back online.

Maybe also debouncing the mousemoves (rxjs debounceTime()) might help, unless you really need to track every mousemove?

One more optimization if you already didn't, add trackBy: yourTrackByFn to the ngFor(s).

funkizer
  • 4,626
  • 1
  • 18
  • 20