No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

11 Días
21 Hrs
51 Min
14 Seg

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?

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.

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

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(‘img’) set onChangeImg(img:string) ⇒ Declara la función para crear un observable del cambio en los datos enviados desde un componente padre
    • @Input(‘img’) ⇒ Declara que se va a recibir una variable.
      • (‘img’) ⇒ 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

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!!!