Angular input change detection performance with mat table data source
Asked Answered
R

0

6

Does anyone know if updating a mat table data source in the ngOnChanges lifecycle hook is ok? Or is there a potential data leak or performance concern at scale?

Here is a simple example of what I mean.

A child component has a parent component that inputs data, like so:

<data-list [data]="someData"></data-list>

and the child component:

import { Component, Input, SimpleChanges, OnInit, OnChanges } from '@angular/core';
import { MatTableDataSource } from '@angular/material';


@Component({
  selector: 'data-list',
  templateUrl: './data-list.component.html',
  styleUrls: ['./data-list.component.scss']
})
export class DataListComponent implements OnInit, OnChanges {
  @Input() data: any[];

  dataSource: MatTableDataSource<any>;
  displayedColumns = [
    'title',
    'detail'
  ];

  constructor() { }

  ngOnInit() {
    this.dataSource = new MatTableDataSource<any>(this.data);
  }

  ngOnChanges(changes: SimpleChanges) {
    this.dataSource = new MatTableDataSource<any>(changes.data.currentValue);
  }

}

Now the parent component is subscribed to different observables that react to different changes to the data. That is, if data is added or removed, the parent component is updated accordingly which it passes along as an input into the child component.

And since the child component is using the ngOnChanges lifecycle hook to watch for changes in the input data, the child component updates the table data by instantiating a new MatTableDataSource.

Everything works just dandy. Except that the ngOnChanges fires often and I'm wary to instantiate a new table source every single time -- as in, it makes me nervous.

I know that this child component could just subscribe to the changes and be in charge of the data rather than receive it from a parent component, but I would rather keep the "smart" and "dumb" component relationship if I can.

Is anyone doing things this way at scale or in production? Is this ok? Am I just being neurotic because I've been staring at my computer screen for the better half of the last 24 hours?

Russon answered 6/3, 2018 at 23:37 Comment(5)
I actually was working on this exact issue for a few hours today, so far the best option I've found is to actually bind the dataSource to the child component via the parent as the updates to the parent rendered immediately whereas the downstream updates when data was passed to the child were visually noticeable.Cowardice
@WillRu what do you mean exactly by "bind the dataSource to the child component via the parent"? Are you saying that you new up the MatTableDataSource in the parent and pass it in as an input into the child?Russon
As an aside, one thing I have discovered is that a performance bottleneck my app is hitting directly relates to Angular change detection. Changing the change detection strategy from "CheckAlways (default)" to "OnPush" for some of my slower components helps dramatically. This does require some care on a per component basis -- I found this article helpful.Russon
Great article there. I was passing the datasource in but ended up changing my approach after encountering further issues with pagination downstream and now use a service to update just the data in the datasource via this.dataSource.data = ... instead of creating a new table each update. That seemed to help resolve some performance issues.Cowardice
hi @WillRu I am stucked to similar problem, Can you give any working example. how you made it work.Grecian

© 2022 - 2024 — McMap. All rights reserved.