No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

ngDestroy and SetInput

7/20
Recursos

El hook ngOnDestroy() & SetInput tiene una importancia clave para el cuidado de nuestra aplicaci贸n. Su funcionalidad m谩s importante es la liberaci贸n de espacio en memoria de variables para que no se acumule. Si esto llegara a suceder en tu aplicaci贸n, la misma podr铆a volverse lenta y tosca a medida que toda la memoria del navegador es ocupada.

Liberando espacio de memoria

Todo el ecosistema Angular est谩 basado en observables para el manejo asincr贸nico.

Cada vez que utilices un subscribe() para escuchar la respuesta de alg煤n evento asincr贸nico (por ejemplo, el llamado a una API), es relevante realizar el respectivo unsubscribe() para liberar ese espacio en memoria.

RxJS

RxJS (Reactive Extensions Library for JavaScript) es una popular librer铆a de Javascript para el manejo de observables. Si trabajas con Angular esta librer铆a ser谩 tu mejor amiga.

Observa el siguiente ejemplo donde primero se importa Subscription desde rxjs para tipar la variable suscription. Guardamos el observable para posteriormente darlo de baja. Tambi茅n importamos interval que devuelve el observable y genera un contador que emite una pulsaci贸n, en este ejemplo, cada 1000 milisegundos.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription, interval } from 'rxjs';

@Component({
  selector: 'app-test-name',
  templateUrl: './test-name.component.html',
  styleUrls: ['./test-name.component.less']
})
export class TestNameComponent implements OnDestroy, OnInit {

    count = interval(1000);
    suscription!: Subscription;

    ngOnInit(): void {
        this.suscription = this.count.subscribe(d => {
          console.log("contando:", d);
        })
    }

    ngOnDestroy(): void {
        this.suscription.unsubscribe();
    }

}

En el ngOnInit(), se est谩 suscribiendo a la propiedad this.count para imprimir por consola, cada 1000 milisegundos, el contador. Podr谩s observar en la consola del navegador el contador corriendo:

ngDestroy & SetInput.png

Si nuestro c贸digo acabara aqu铆, cuando el componente es destruido, el contador continuar铆a ocupando memoria que ya no deber铆a ser utilizada.

Para solucionar esto, guardamos en this.suscription el observable del contador y en ngOnDestroy() y llamamos al m茅todo .unsubscribe() para detener el contador.


Contribuci贸n creada con los aportes de Kevin Fiorentino.

Aportes 33

Preguntas 14

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

explica medio confuso, toma como ejemplo img pero en realidad son strings y se siente que no hay estructura igual podria dar un ejemplo mas practico para usar el ngOnDestroy y ngOnChanges luego el ingles鈥 no es todo malo pero todos los cursos de angular los da el y a veces cansa escuchar a la misma persona (pasaria con cualquier profesor jaja)

Son dos clases en una esta.
Primero hay que entender el uso de ngOnDestroy() para liberar espacio de memoria cuando un componente se destruye desuscribiendo observables, por ejemplo.
Otra cosa es el SetInput para estar escuchando cambios en un @Input(). Es muy 煤til realmente, yo lo he utilizado mucho.
Es avanzado, mastiquenlo despacio y lean la documentaci贸n oficial para entenderlo.

En el min 8:24 hace un cambio repentino de tema, bien podr铆an ser 2 videos uno para ngDestroy y otro para SetInput

El profe es muy bueno! Pero primera vez en sus cursos que me pierdo, podr铆an haber dividido estos dos temas en dos videos.

Window.clearInterval(this.counterFc); no es lo mismo que window.clearInterval(this.counterFc);
La mayuscula inicial no permite correrlo de forma correcta.

Podemos utilizar este m茅todo para convertir en observable a un input, de esa manera al momento de un cambio, podemos decidir que hacer con el y aplicar c贸digo de ser necesario

Lo utilizamos de la siguiente manera:

@Input()
set nombreInput(valorInput: string){
	this.variableComponente =  valorInput
	//aqui va el codigo que se ejecutara al cambiar el valor del input
}

que forma mas curiosa de realizar un watcher con Angular

<code> prop_img: string = '';

  @Input('prop_img')
  set changeImg(newImg: string){
    this.prop_img = newImg;
  }

馃榿

ngDestroy and SetInput


Liberando espacio de memoria

Todo el ecosistema Angular est谩 basado en observables para el manejo asincr贸nico.

En Angular, puedes liberar espacio de memoria al destruir un componente o directiva que ya no se est谩 utilizando. Cuando Angular destruye un componente o directiva, libera autom谩ticamente todos los recursos que se asignaron a ella.

Sin embargo, en algunos casos, es posible que debas realizar tareas adicionales para liberar espacio de memoria. Por ejemplo, si tu componente o directiva ha creado un observable o ha suscrito a uno, es posible que debas cancelar la suscripci贸n para evitar fugas de memoria.

RxJS

RxJS聽(Reactive Extensions Library for JavaScript) es una popular librer铆a de Javascript para el manejo de observables. Si trabajas con Angular esta librer铆a ser谩 tu mejor amiga

Para cancelar una suscripci贸n, debes almacenar la suscripci贸n en una variable y luego llamar al m茅todo unsubscribe() en la variable cuando el componente se destruye. Aqu铆 te presento un ejemplo:

import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { MiServicio } from './mi-servicio';

@Component({
  selector: 'app-mi-componente',
  templateUrl: './mi-componente.component.html',
  styleUrls: ['./mi-componente.component.css']
})
export class MiComponente implements OnDestroy {
  private subscription: Subscription;

  constructor(private miServicio: MiServicio) {
    this.subscription = this.miServicio.miObservable.subscribe();
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}

En este ejemplo, el componente MiComponente tiene una propiedad subscription que almacena la suscripci贸n al observable. En el constructor, se suscribe al observable a trav茅s del servicio MiServicio. Luego, en el m茅todo ngOnDestroy, se llama al m茅todo unsubscribe() en la variable subscription para cancelar la suscripci贸n.

De esta manera, cuando el componente se destruye, la suscripci贸n se cancela y los recursos asignados al observable se liberan, evitando posibles fugas de memoria.

Es importante identificar y corregir las fugas de memoria en Angular, ya que pueden provocar que la aplicaci贸n consuma m谩s memoria de la necesaria, lo que puede afectar el rendimiento y la experiencia del usuario.

Input setter coercion

En Angular, los decoradores @Input se utilizan para exponer propiedades p煤blicas de un componente para que puedan ser establecidas desde otros componentes. Cuando se establece el valor de una propiedad de entrada mediante @Input, Angular ejecuta autom谩ticamente la l贸gica de detecci贸n de cambios para actualizar la vista y los modelos de datos correspondientes.

En algunos casos, es posible que desees aplicar una conversi贸n o validaci贸n al valor de entrada antes de establecerlo en la propiedad del componente.

  • Por ejemplo, es posible que desees asegurarte de que un valor de entrada sea un n煤mero entero antes de establecerlo en una propiedad que espera un n煤mero.

Para abordar esta necesidad, Angular proporciona una caracter铆stica llamada Input setter coercion. Este mecanismo permite definir un m茅todo de conversi贸n o validaci贸n que se ejecuta autom谩ticamente cuando se establece el valor de entrada de una propiedad del componente. Este m茅todo se define en la propiedad de entrada mediante un decorador @Input modificado con el modificador set.

El m茅todo de conversi贸n o validaci贸n debe tener el mismo nombre que la propiedad de entrada, seguido de la palabra Change. El m茅todo toma un solo argumento que representa el nuevo valor de la propiedad de entrada. Aqu铆 te presento un ejemplo de c贸mo se utiliza:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-mi-componente',
  templateUrl: './mi-componente.component.html',
  styleUrls: ['./mi-componente.component.css']
})
export class MiComponente {
  private _miPropiedad: number;
  @Input() set miPropiedad(value: number) {
    this._miPropiedad = Math.floor(value);
  }
  get miPropiedad(): number {
    return this._miPropiedad;
  }
}

En este ejemplo, el componente MiComponente tiene una propiedad de entrada llamada miPropiedad, que se define mediante el decorador @Input. El m茅todo de conversi贸n o validaci贸n se define mediante el modificador set y se llama miPropiedadChange. Este m茅todo utiliza la funci贸n Math.floor para convertir el valor de entrada a un n煤mero entero y establece el resultado en la propiedad privada _miPropiedad.

  • Es importante tener en cuenta que el m茅todo de conversi贸n o validaci贸n solo se ejecuta cuando se establece el valor de entrada mediante la sintaxis de enlace de propiedades [miPropiedad]. Si se establece el valor de entrada directamente en la propiedad del componente, el m茅todo de conversi贸n o validaci贸n no se ejecutar谩.

El mecanismo de Input setter coercion puede ser 煤til para simplificar el c贸digo y asegurar que los valores de entrada se ajusten a los requisitos del componente. Sin embargo, debes tener cuidado al utilizarlo para no introducir comportamientos inesperados o dificultades de depuraci贸n. Es importante documentar claramente la funci贸n de conversi贸n o validaci贸n y asegurarse de que se comporte de manera consistente en todas las situaciones.

No veo un uso practico para el ngOnChange(), ser铆a estupendo que nos mostrara como manipular cada cambio dentro del ngOnChange() el cual es el encargado de gestionar los cambios de estado de los @Inputs. pero por lo visto es mejor gestionarlos desde un setInput

ngOnDestroy(): Se llama solo una vez, justo antes de que Angular destruya el componente, y sirve para prevenir memory leaks, eliminando por ejemplo suscripciones a Observables e event handlers

Aqui les dejo un recurso de la documentacion oficial donde podemos complementar los ejemplos:

#AguanteAngular

Las clases me han parecido interesantes, pero cuando el profesor hace un comentario como setInterval realmente no es una buena pr谩ctica, uno esperar铆a que con su experiencia indicara como evitarlo, que otras alternativas existen, pero decir no es una buena pr谩ctica y vamos a usarla. Es algo contradictorio.

Pienso que el SetInput debi贸 venir como una clase despu茅s de la anterior que vimos y el ngDestroy despu茅s de la de SetInput.

8:25 se nota el corte con cambio de tema

dificil de entender, muy complicada la explicacion, me termina de complicar pero se nota que nicolas es un trome鈥

Profe, primera vez que me hizo ver la clase dos veces porque no le entend铆 el valor, o utilidad al setInput y porque utilizarlo sobre el ngOnChange

A mi me qued谩 bastante claro

ngDestoy & SetInput

Algunos eventos pueden seguir ejecut谩ndose aunque su componente ya haya sido destruido. Esto es un problema.

Por ejemplo, tenemos un contador en la UI:

import {
  Component,
} from '@angular/core';

@Component({
  selector: 'app-img',
  templateUrl: './img.component.html',
  styleUrls: ['./img.component.scss']
})
export class ImgComponent {
  ngOnInit(): void {
    this.counterFn = window.setInterval(() => {
      this.counter += 1;
      console.log('running counter');
    }, 1000)
  }

  ngOnDestroy(): void {
    window.clearInterval(this.counterFn);
    //* usamos esto para que el interval no se siga ejecutando
  }
}

<h3>{{ counter }}</h3>
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  showImage: boolean = true;

  toggleImage() {
    this.showImage = !this.showImage;
  }
}

<button (click)="toggleImage()">Toggle image</button>

<p> {{ showImage }} </p>

<app-img
  *ngIf="showImage"
  (loaded)="onLoaded($event)"
  [img]="imgParent"
>
</app-img>

Explicaci贸n OnDestroy

ngDestroy

Este hook se ejecuta cada vez que eliminamos un componente de nuestro espacio de renderizado. Debemos tener cuidado de eliminar las instancia de procesos que llamamos en alg煤n punto de la aplicaci贸n que quedan vivos una vez son instanciados sin importar que el componente desde donde se crearon haya sido eliminado.

Por ejemplo, los m茅todos de window no son destruidos si los llamamos desde un componente creado por nosotros. Es necesario que despu茅s de ser instanciados se eliminen de la memoria manualmente.

Veamos el m茅todo window.setInterval que no es recomendable usar en una aplicaci贸n pero nos servira para ilustrar lo antes mencionado. En nuestro componente img creemos un contador que se activara una vez el componente ha sido creado y se mostrar谩 su valor en pantalla.

img.component.html

<img [src]="img" alt="image" (load)="imageLoad(img)" (error)="imageError()" width="100" *ngIf="img; else elseImg">
<p>Contador = {{contador}}</p>
<ng-template #elseImg>
  <img [src]="imgDefalult" alt="image" width="100">
</ng-template>

img.component.ts

Deseamos que el contador se cree justo despu茅s de ser renderizado el componente por eso usamos el OnInit

import { Component, Input, Output, EventEmitter, **OnInit, OnDestroy** } from '@angular/core';

@Component({
  selector: 'app-img',
  templateUrl: './img.component.html',
  styleUrls: ['./img.component.scss']
})
export class ImgComponent implements **OnInit, OnDestroy** {
  @Input() img:string = '';
  @Output() loader = new EventEmitter<string>();
  imgDefalult = './assets/images/default.png';

  **contador:number = 0;**

  imageError(){
    this.img = this.imgDefalult;
  }
  imageLoad(img:string){
    console.log("Desde el hijo ", img);
    this.loader.emit(`imgUrl: ${img}`);
  }
  **ngOnInit(): void {
    window.setInterval(()=>{
      console.log(this.contador);
      this.contador += 1;
    }, 1000)
  };
  ngOnDestroy(): void {
    console.log('OnDestroy');
  }
}**

Ahora en nuestro componente app vamos a crear un bot贸n del cual depende si mostramos o eliminamos la imagen de la pantalla.

app.component.html

La variable togleImageState define si mostramos el componente img o no en el espacio render. Entre tanto la func铆on togleImg() cambia el valor de nuestra variable de control togleImageState

**<h1>Store App / App</h1>
<input type="text" [(ngModel)]="imgParent"/>
<button type="button" (click)="togleImg()">Eliminar imagen</button>**
<app-img ***ngIf="togleImageState"** img={{imgParent}} (loader) = "receiveMessage($event)"></app-img>
<app-product *ngFor="let product of products" [product]="product"></app-product>

app.component.ts

import { Component } from '@angular/core';
import { Product } from './models/product.model';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
	**togleImageState = true;**
  title = 'store-app';
  imgParent = '';
  products : Product[] = [
    {
      id:'1',
      name: 'TV',
      image: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRQSKo3CiTvzWfRKUAfpRYnmHEZOvMsGqIOhQ&usqp=CAU",
      price: "100"
    },
    {
      id:'2',
      name: 'Patines',
      image: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQAKixvg6J_6jwCRTNGteSRfopgayrIpKDCI9_oQ6-n2CCXrnMp0uNRs0wAP2a-nPvrMNs&usqp=CAU",
      price: "50"
    },
    {
      id:'3',
      name: 'Bicicleta',
      image: "https://bicistore.com.co/wp-content/uploads/2020/11/imagen-5.jpg",
      price: "70"
    },
    {
      id:'4',
      name: 'Pc Gamer',
      image: "https://gamerspit.com.ar/wp-content/uploads/2021/07/pc-gamer-armada-gabinete-rgb-1-2-450x450.png",
      price: "800"
    }
  ]
  **receiveMessage(img : string) {
    console.log("Desde el padre", img);
  }
  togleImg(){
    this.togleImageState = !this.togleImageState;
  }**
}

Tenemos toda la estructura lista para el ejemplo. Al dar click sobre el bot贸n debemos ver como aparece y desaparece la imagen de la pantalla. 隆Pero en consola el contador sigue apareciendo aun cuando se ejecuto el m茅todo ngOnDestroy!

Soluci贸n

Para solucionar el fallo, debemos guardar la instancia del m茅todo window.setInterval en una variable. De esta manera podemos eliminar su valor en el m茅todo ngOnDestroy. Esto es necesario debido a que el m茅todo window.setInterval podriamos decir se instancia de manera global no localmente sobre el componente.

import { Component, Input, Output, EventEmitter, **OnInit, OnDestroy** } from '@angular/core';

@Component({
  selector: 'app-img',
  templateUrl: './img.component.html',
  styleUrls: ['./img.component.scss']
})
export class ImgComponent implements **OnInit, OnDestroy** {
  @Input() img:string = '';
  @Output() loader = new EventEmitter<string>();
  imgDefalult = './assets/images/default.png';

  **contador:number = 0;
  counterFn : number | undefined;**

  imageError(){
    this.img = this.imgDefalult;
  }
  imageLoad(img:string){
    console.log("Desde el hijo ", img);
    this.loader.emit(`imgUrl: ${img}`);
  }
  **ngOnInit(): void {
    this.counterFn = window.setInterval(()=>{
      console.log(this.contador);
      this.contador += 1;
    }, 1000)
  };
  ngOnDestroy(): void {
    console.log('OnDestroy');
    window.clearInterval(this.counterFn);
  }
}**

Explicaci贸n set Input()

set Input()

El m茅todo OnChange se activa con cualquier cambio que se presente dentro de nuestro componente. Uno de los casos que hace que se dispare este m茅todo es un cambio en el valor de una variable que recibe datos desde un componente padre. En otras palabras cualquier variable de tipo Input() hace que OnChange se dispare.

El evento OnChange registra los datos del cambio en un array con los valores que cambiaron en determinado evento de cambio. Estos cambios los podemos detectar usando una variable.

ngOnChanges (changes: SimpleChanges) {
	console.log("Cambios detectados", changes);
}

Si deseas aplicar una l贸gica cuando se produzca un cambio especifico en una variable y deseas usar el m茅todo ngOnChanges debes aplicar una sentencia if que reaccione solo cuando la variable que estas declarando en este ejemplo changes para detectar el cambio SimpleChanges tome un valor especifico.

ngOnChanges (changes: SimpleChanges) {
	console.log("Cambios detectados", changes);
	if(changes.){
		//Logica para el cambio
	}
}

Esto es dif铆cil de controlar y en componentes con demasiados eventos puede ser complejo.

En estos casos donde deseamos detectar un cambio de un input especifico podemos usar un Input que en lugar de cambiar el valor de una variable invoque una funci贸n donde podemos aplicar l贸gica seg煤n nuestros objetivos similar a un observador. Su sintaxis es simple y f谩cil de implementar

La estructura requiere dos cosas una variable donde se guarden los datos recibidos para usarlos en el componente y una funci贸n

img:string = '';
@Input('img') set onChangeImg(img:string){
  this.img = img;
}
  • img:string = 鈥樷; 鈬 Variable local donde guardamos los datos externos
  • @Input(鈥榠mg鈥) set onChangeImg(img:string) 鈬 Declara la funci贸n para crear un observable del cambio en los datos enviados desde un componente padre
    • @Input(鈥榠mg鈥) 鈬 Declara que se va a recibir una variable.
      • (鈥榠mg鈥) 鈬 Esta declaraci贸n sirve para usar un alias. En este caso indica que la variable en el componente padre se llama img y si cambia su valor se debe ejecutar la funcion
      • Es opcional, si no lo usamos en el componente padre la variable debe tener como nombre el de la funci贸n, en este caso onChangeImg
  • onChangeImg(img:string) 鈬 Es el nombre de la funci贸n e indicamos que en ella llegaran datos instanciados en la variable img que es de tipo string. NO confundir este valor con la variable img del componente.
  • this.img = img; 鈬 En este paso se asignan los valore externos de la variable img que lleg谩n desde el componente padre a nuestro variable del componente this.img

El componente padre puede mantener la misma estructura al usar el alias dentro de nuestro componente hijo img.

app.component.html

<h1>Store App / App</h1>
<input type="text" [(ngModel)]="imgParent"/>
<button type="button" (click)="togleImg()">Eliminar imagen</button>
<app-img *ngIf="togleImageState" **img={{imgParent}}** (loader) = "receiveMessage($event)"></app-img>
<app-product *ngFor="let product of products" [product]="product"></app-product>

app.component.ts

import { Component } from '@angular/core';
import { Product } from './models/product.model';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'store-app';
  togleImageState = true;
  imgParent = '';
  products : Product[] = [
    {
      id:'1',
      name: 'TV',
      image: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRQSKo3CiTvzWfRKUAfpRYnmHEZOvMsGqIOhQ&usqp=CAU",
      price: "100"
    },
    {
      id:'1',
      name: 'Patines',
      image: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQAKixvg6J_6jwCRTNGteSRfopgayrIpKDCI9_oQ6-n2CCXrnMp0uNRs0wAP2a-nPvrMNs&usqp=CAU",
      price: "50"
    },
    {
      id:'1',
      name: 'Bicicleta',
      image: "https://bicistore.com.co/wp-content/uploads/2020/11/imagen-5.jpg",
      price: "70"
    },
    {
      id:'1',
      name: 'Pc Gamer',
      image: "https://gamerspit.com.ar/wp-content/uploads/2021/07/pc-gamer-armada-gabinete-rgb-1-2-450x450.png",
      price: "800"
    }
  ]
  receiveMessage(img : string) {
    console.log("Desde el padre", img);
  }
  togleImg(){
    this.togleImageState = !this.togleImageState;
  }
}

La verdad que este curso me est谩 mareando mucho, empece contento pero ahora me estoy planteando que hacer de mi vida jaja confunde demasiado, explica demasiado apurado, como si lo estuviera haciendo de onda.
Los ejemplos tambi茅n son poco pr谩cticos y hasta tediosos de seguir o escuchar, no son para nada creativos. Y me encanta como ense帽a Nico pero no s茅, me esta confundiendo MUCHISIMO, estar铆a bueno que hicieron un curso nuevo de Angular mejor estructurado y mas enfocado a la pr谩ctica.

En esta parte del curso ya me siento perdido :C

Me gust贸 la explicaci贸n del profesor pero ampli茅 la parte del SetInput con este video que me pareci贸 muy bueno:

https://www.youtube.com/watch?v=t5n_sAqQSqg

es complicado entender a la primera hay que repetir la clase y repasar, saludos yo tambi茅n estoy aprendiendo.

Iva tan bien, hasta que llegue a esta clase, esta buena por que es retadora, pero si creer铆a que hay que dedicarle su respectivo tiempo a cada uno de los temas.

En este post se explica con m谩s detalles el uso de SetInput.

IMPORTANTE la funci贸n setInterval() Retorna un numero ID al ser llamada este numero ID es el que guardamos para despues en el ngOnDestroy poder decirle con clearInterval() que detenga el intervalo que creamos para mas info鈥 leer el siguiente link
https://developer.mozilla.org/en-US/docs/Web/API/setInterval

Clase terrible, por favor, hagan caso a los comentarios, revisen el material. La de tiempo que llevo perdido en este video y seg煤n leo para nada, y espero que as铆 sea porque no consigo que funcione el c贸digo ni a tiros. Por favor, atiendan a lo que dicen los compa帽eros.

Aparte del setInterval y setTimeOut, yo te presento a pointerMove, podr谩s verlo a trav茅s de Events, si activas pointerMove, tendras que eliminarlo con ngOnDestroy(), para evitar problemas de rendimiento.

SetInput

Concuerdo con muchas de las personas que ya vieron este v铆deo. de este v铆deo salen dos clases distintas y bien explicadas. yo me sent铆a bien confundido por eso

mucha cosa para un input, me perdi

Hola, tengo una consulta, como harian el siguiente ejercicio que estoy intentando hacer pero creo que lo estoy haciendo mal;
4)Usuarios podran buscar todos los conciertos por el nombre de la banda.
Explique con sus palabras que elementos provistos
por Angular utilizar铆a para la b煤squeda 100% en Angular y realice un pseudoc贸digo
solamente del HTML del componente.

Gracias!!!