Performance issue while rendering multiple editors in `ngFor` loop
Mgsy opened this issue · 3 comments
Mgsy commented
Steps to reproduce
- Clone the example project - https://github.com/raziahmadansari/editor-demo
- Run
npm i && ng serve
- Visit the sample
- Click "Add editor" button a few times
Rendering method:
<ng-container *ngFor="let editor of editors; index as editorId">
<app-editor [editorInstanceId]="editorId"></app-editor>
</ng-container>
Current result
Each time the editor is added, the browser starts responding slower, until it freezes.
Notes
- The same amount of editors rendered at once doesn't cause any issues
Reinmar commented
To be checked:
- Is this
ngFor
use correct? What abouttrackBy
e.g.? This may help already. - Isn't this made worse by a memory leak. Check e.g. for
console.logs( editor )
because it gets the editor instances retained forever.
Mgsy commented
The issue is caused by the fact that all editors re-render after adding a new editor. The solution is to make sure that only one component is added, without triggering rendering of all of them.
Mgsy commented
Full solution: https://github.com/raziahmadansari/editor-demo/tree/main/src/app/loop-demo
The example mechanism for rendering components with trackBy
:
loop-demo.component.html
<h1>CKEditor Demo</h1>
<ng-container
*ngFor="let editor of editors; index as editorId; trackBy: trackEditor"
>
<div class="mb-10">
<app-editor
class="mb-10"
[editorInstanceId]="editorId"
(onEditorReady)="onReady($event)"
></app-editor>
</div>
</ng-container>
<button type="button" (click)="addEditor()">+ Add Editor</button>
<button type="button" (click)="removeEditors()" class="ml-10">
X Remove Editors
</button>
loop-demo.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-loop-demo',
templateUrl: './loop-demo.component.html',
styleUrl: './loop-demo.component.scss',
})
export class LoopDemoComponent implements OnInit {
editors: Array<any> = [];
ngOnInit(): void {
// this.loadEditors(4);
}
loadEditors(editorCount: number): void {
for (let editorId = 0; editorId < editorCount; editorId++) {
this.editors.push(editorId);
}
}
addEditor(): void {
this.editors.push(this.editors.length);
}
removeEditors(): void {
this.editors = [];
}
onReady(editor: any): void {
// this.editors[this.editors.length - 1] = editor;
}
trackEditor(index: number, item: any): number {
return item;
}
}