Improving Angular Rendering Performance with TrackBy and Change Detection Strategy
Tags: angular, javascript, typescript, angularperformanceimprovement
Published: 2023-05-08 17:39:31

- Flickering in Angular applications can be caused by inefficient rendering, which can happen when the browser has to re-render the entire DOM for a component or list every time a change occurs. This can be especially problematic for large or complex applications.

- To prevent flickering, developers can use the TrackBy function and OnPush change detection strategy to improve performance and reduce unnecessary rendering. These techniques can help provide a better user experience in Angular apps. 

**Lets dive into the Action**

1. Let's say you have a component that displays a list of ITEMS, and each item has an ID, a name, and a description. The list is updated frequently, either by adding new items or by changing the properties of existing items. You want to make sure that when the list is updated, only the items that have changed are re-rendered, and not the entire list.

2. This is where the TrackBy function comes in. The TrackBy function is used to tell Angular how to track changes in the list items, so that it can identify which items have changed and only update those.

```
// item.component.ts
@Component({
  selector: 'app-item',
  templateUrl: './item.component.html',
})
export class ItemComponent {
  @Input() item: Item;
}

// item.component.html
<div>
  <h2>{{ item.name }}</h2>
  <p>{{ item.description }}</p>
</div>

// list.component.ts
@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
})

export class ListComponent {
  items: Item[];

  constructor(private service: ItemService) {
    this.items = this.service.getItems();
  }

  trackByFn(index: number, item: Item) {
    return item.id;
  }
}

// list.component.html
<ul>
  <li *ngFor="let item of items; trackBy: trackByFn">
    <app-item [item]="item"></app-item>
  </li>
</ul>

```

3. In above example, we have an Item component that displays the details of a single item, and a List component that displays a list of items using the *ngFor directive. 

4. The trackByFn function is used to tell Angular how to track changes in the list items. In this case, we're using the item's ID as the key to track changes. This means that when a new item is added to the list or an existing item's properties are changed, Angular will only re-render the specific item, instead of re-rendering the entire list.

5. By using the TrackBy function in this way, we can significantly improve the rendering performance of our Angular application, especially for large or complex lists.

## Change Detection Strategy

In this section, we'll explain how the change detection strategy can help improve application performance.

before getting into the point let's discuss what is this changeDetectionStrategy in Angular.

-  Change Detection is the process by which Angular keeps track of changes in a component's state and updates the view accordingly. By default, Angular uses the "Default".

**Change Detection Strategies in Angular:**

1. **Default**: This is the default Change Detection Strategy in Angular. It checks every component and its children for changes on each cycle of the event loop.

2. **OnPush**: This Change Detection Strategy checks for changes only when the component's @input properties change, or when an event is fired from the component or one of its children. we need to add a **changeDetection** property in **component decorator** to use this.

```
@Component({
  selector: 'app-example-list',
  templateUrl: './example-list.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleListComponent implements OnInit {
  @Input() items: ExampleItem[];

  trackByFn(index: number, item: ExampleItem): number {
    return item.id;
  }
}


```

3. **Detached**: This Change Detection Strategy disables Change Detection for the component and its children. This can be useful when a component is not expected to change, or when we want to manually trigger Change Detection later. With the Detached strategy, Angular will not check for changes in the component or its children until we manually trigger Change Detection using the ChangeDetectorRef.detectChanges() method.

> However, we should be careful and make sure to manually trigger Change Detection when necessary to avoid issues with the view not updating correctly.

```
@Component({
  selector: 'app-large-list',
  templateUrl: './large-list.component.html',
  changeDetection: ChangeDetectionStrategy.Detached
})
export class LargeListComponent {
  @Input() items: LargeListItem[];
  private isListVisible = false;

  constructor(private cd: ChangeDetectorRef) {}

  showList(): void {
    this.isListVisible = true;
    this.cd.detectChanges();
  }
}

```

**I hope you find this post helpful. Thanks for reading.**