Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it normal for Angular to re-render infinitely even when no changes are made?

The question

Is Angular designed to constantly re-check everything in order to detect changes? I'm coming from the React world and I was expect something like event triggered -> re-rendering. I don't know if this is something from my app or something from Angular.

If I have a method that's called from the HTML Template, it gets called infinitely even if nothing in my component changes.

The problem

I have a calendar-like page that loads a lot of data and has to compute things before rendering, because it would be too difficult to do these things with the ngIf directive. So I have things in my template that look like:

<div [innerHTML]="_getDayPrice(item, day) | safeHtml"></div>  

If I console log something in the _getDayPrice method, it gets printed infinitely.

What I've tried

  1. I've managed to bypass this by manually injecting the ChangeDetectionRef in my app and doing this.cdRef.detach(). This however feels hacky as sometimes I might need to re-enable it and detach again.

  2. I've tried to investigate if it's something from my parent component apps, like containers. I've rendered in my main app.component a single div like <div class={{computeClass()}}> and in that method printed a console log and sure enough it gets called infinitely. So following this I've tried commenting-out all of the apps' services. If all are commented out sure enough it works properly, but also there's no observable data. I've investigated for about half a day and couldn't find a single point of failure (like commenting out this service fixes everything).

  3. Record performance using chrome's built-in Performance tab, but again couldn't find anything from my code that triggers changes. zone.js gets called repeatedly and appears to set an interval that keeps firing.

  4. Of course I've searched for occurrences of setTimeout and setInterval in the services but couldn't find something that keeps getting changed that might cause this issue.

Conclusion?

Bottom line is: is it normal, if you have a complex Angular app and call a method from the template, for that method to be called infinitely?

And if not, do you have any hints as to what might be causing this? Or any other means to bypass it rather than detaching the changeRef detector?

My only concern is with performance. It's a calendar-like page that renders multiple-rows, and it lags pretty severely on a 8GB RAM laptop. I'm pretty sure that a tablet or a phone would almost freeze.

like image 665
Raul Rene Avatar asked Jun 25 '18 11:06

Raul Rene


People also ask

How do you prevent re-rendering of components that have not changed?

1. Memoization using useMemo() and UseCallback() Hooks. Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.

How can you prevent re-rendering a total component?

If you're using a React class component you can use the shouldComponentUpdate method or a React. PureComponent class extension to prevent a component from re-rendering.

What causes a re-render React?

When React component re-renders itself? There are four reasons why a component would re-render itself: state changes, parent (or children) re-renders, context changes, and hooks changes. There is also a big myth: that re-renders happen when the component's props change.

Does useMutation cause Rerender?

Usually, useMutation does not trigger re-render until you are subscribed to some values inside the cache.


Video Answer


1 Answers

You should use pipes as often as possible when transforming data in your HTML.

Pipes are only re-evaluated when the piped object or parameters change (so if one of the inputs is an object, make sure to create a new instance of that object to trigger re-evaluation). For most uses, you can use a pipe rather that an function.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'getDayPrice'
})
export class GetDayPricePipe implements PipeTransform {

  transform(item: string, day: string): string {
    // ... do whatever logic here
    return item + day;
  }

}

Then use it like that :

<div [innerHTML]="item | getDayPrice:day | safeHtml"></div>
like image 173
JusuVh Avatar answered Sep 25 '22 13:09

JusuVh