Skip to content

Commit 18f46cf

Browse files
crisbetojelbourn
authored andcommitted
refactor(grid-list): avoid recreating tile coordinator for every change detection (#13226)
Currently we recreate the `TileCoordinator` and throw out the old one on every change detection run. These changes reuse a single `TileCoordinator` and update it instead, which ends up shaving off a couple of milliseconds off each layout and reduces the amount of objects that need to be garbage collected. **Note:** this is a breaking API change for the `TileCoordinator`, however it isn't exported through `material/grid-list`.
1 parent 0ac41a0 commit 18f46cf

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

src/lib/grid-list/grid-list.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export class MatGridList implements OnInit, AfterContentChecked {
4747
/** Number of columns being rendered. */
4848
private _cols: number;
4949

50+
/** Used for determiningthe position of each tile in the grid. */
51+
private _tileCoordinator: TileCoordinator;
52+
5053
/**
5154
* Row height value passed in by user. This can be one of three types:
5255
* - Number value (ex: "100px"): sets a fixed row height to that value
@@ -135,8 +138,14 @@ export class MatGridList implements OnInit, AfterContentChecked {
135138

136139
/** Computes and applies the size and position for all children grid tiles. */
137140
private _layoutTiles(): void {
138-
const tracker = new TileCoordinator(this.cols, this._tiles);
141+
if (!this._tileCoordinator) {
142+
this._tileCoordinator = new TileCoordinator(this._tiles);
143+
}
144+
145+
const tracker = this._tileCoordinator;
139146
const direction = this._dir ? this._dir.value : 'ltr';
147+
148+
this._tileCoordinator.update(this.cols);
140149
this._tileStyler.init(this.gutterSize, tracker, this.cols, direction);
141150

142151
this._tiles.forEach((tile, index) => {

src/lib/grid-list/tile-coordinator.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class TileCoordinator {
4444
* Ex: A list with 1 row that contains a tile with rowspan 2 will have a total rowspan of 2.
4545
*/
4646
get rowspan() {
47-
let lastRowMax = Math.max(...this.tracker);
47+
const lastRowMax = Math.max(...this.tracker);
4848
// if any of the tiles has a rowspan that pushes it beyond the total row count,
4949
// add the difference to the rowcount
5050
return lastRowMax > 1 ? this.rowCount + lastRowMax - 1 : this.rowCount;
@@ -53,17 +53,25 @@ export class TileCoordinator {
5353
/** The computed (row, col) position of each tile (the output). */
5454
positions: TilePosition[];
5555

56-
constructor(numColumns: number, tiles: QueryList<MatGridTile>) {
56+
constructor(private _tiles: QueryList<MatGridTile>) {}
57+
58+
/**
59+
* Updates the tile positions.
60+
* @param numColumns Amount of columns in the grid.
61+
*/
62+
update(numColumns: number) {
63+
this.columnIndex = 0;
64+
this.rowIndex = 0;
65+
5766
this.tracker = new Array(numColumns);
5867
this.tracker.fill(0, 0, this.tracker.length);
59-
60-
this.positions = tiles.map(tile => this._trackTile(tile));
68+
this.positions = this._tiles.map(tile => this._trackTile(tile));
6169
}
6270

6371
/** Calculates the row and col position of a tile. */
6472
private _trackTile(tile: MatGridTile): TilePosition {
6573
// Find a gap large enough for this tile.
66-
let gapStartIndex = this._findMatchingGap(tile.colspan);
74+
const gapStartIndex = this._findMatchingGap(tile.colspan);
6775

6876
// Place tile in the resulting gap.
6977
this._markTilePosition(gapStartIndex, tile);

0 commit comments

Comments
 (0)