OnPush components normally re-render whenever a new array reference arrives on an @Input, even if the contents are identical — a common source of wasted change detection cycles in list-heavy UIs. This snippet installs a custom setter that runs a structural equality check before accepting the new reference, so a parent that recreates an array with the same logical rows (a frequent pattern with immutable state stores) no longer forces a re-render. Combined with trackBy, this keeps both the component-level CD pass and the DOM reconciliation pass minimal.
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';interface Row { id: string; score: number; }function shallowRowsEqual(a: readonly Row[], b: readonly Row[]): boolean {if (a === b) return true;if (a.length !== b.length) return false;for (let i = 0; i < a.length; i++) {if (a[i].id !== b[i].id || a[i].score !== b[i].score) return false;}return true;}@Component({selector: 'app-leaderboard',changeDetection: ChangeDetectionStrategy.OnPush,template: `<div *ngFor="let row of rows; trackBy: trackById">{{ row.id }}: {{ row.score }}</div>`,})class LeaderboardComponent {private _rows: readonly Row[] = [];@Input() set rows(next: readonly Row[]) {if (!shallowRowsEqual(this._rows, next)) {this._rows = next;}}get rows(): readonly Row[] {return this._rows;}trackById(_index: number, row: Row): string {return row.id;}}