@composi/core:
Ciclo de Vida
Enganches de Ciclo de Vida
Con Composi, los componentes funcionales tienen tres enganches de ciclo de vida que puedes usar:
Los enganches de ciclo de vida te permiten realizar tareas en un momento específico de la vida del componente. También te permiten crear animaciones cuando cambia el estado de un componente.
onmount
El enganche de ciclo de vida onmount
se activa justo después de que el componente se monta en el DOM. Toma un callback cuyo primer argumento es el elemento base del componente. Esto le permite hacer algunas cosas útiles, como acceder a los elementos secundarios del componente, o configurar escuchas de eventos y eventos delegados.
En la documentación de props y events, vimos cómo crear una lista. Ahora vamos a ver cómo agregar elementos a la lista. Para hacer eso, necesitamos tener un input donde el usuario pueda agregar un nuevo ítem y un botón para hacer clic para agregar ese ítem a la lista. El enganche onmount
es una forma de acceder al input del componente para obtener su valor. Entonces, hagamos esto. Vamos a cambiar el ejemplo, envolviendo la lista en un div
que tiene dos hijos, la lista y un párrafo con un input de texto y un botón.
Acceder al DOM del Componente
Para poder acceder al input del componente, debemos agregar un enganche de ciclo de vida onmount
. Lo ponemos directamente en el input. De esa manera, el enganche onmount
obtiene una referencia al elemento input mismo. Luego podemos guardar esa referencia en el objeto refs
para un fácil acceso en el código del componente.
También estamos agregando enganches onmount
a los ítemes de la lista con el único propósito de animarlos cuando se crean. Añade nuevos ítemes a la lista para ver la animación.
See the Pen @composi/core - Ciclo de Vida-onmount by Robert Biggs (@rbiggs) on CodePen.
onupdate
A veces vas a querer saber cuándo un componente se está actualizando, como cuando se cambian sus props
. Puedes realizar esto con onupdate
. Este enganche recibe tres argumentos: el element base del componente, las props
anteriores y las props
nuevas. Puedes comparar las props
para ver cómo cambiaron y así decidir que hacer.
onuptate
se invoca cuando el element particular en el cual está registrado se acutaliza. El enganche onupdate
no es invocado cuando el elemento se monta or desmonta.
Para usar onupdate
correctamente, tienes que entender bien qué son las props
viejas y nuevas. Pasamos las props
a un componente cuando pasamos éste a la función code>render:
render(<Lista datos={frutas}/>, 'body')
Decimos que el atributo datos
es una prop
. Pero, en este caso no va persistir como prop
. Eso es porque la función render
convertirá la etiqueta JSX en una función y sus props
serán los argumentos de aquella función. Tecnicamente, las props
son los valores agregados directamente en los elementos que el componente como función devuele. Vamos a examinar otra vez el componente de Lista:
function Lista({datos}) {
function mostrarCambio(elemento, propsViejas, propsNuevas) {
// compara propsViejas con propsNuevas
}
return (
<ul onupdate={mostrarCambio}>
{
datos.map(ítem => <li key={ítem.clave}>{ítem.valor}</li>)
}
</ul>
)
}
render(<Lista datos={frutas}/>, 'body')
En el ejemplo anterior, fíjate que hemos puest el evento onupdate
directamente en el elemento base del componente. Luego, en nuestra función mostrarCambio
queremos comparar las props
viejas y nuevas para ver qué cambia. Podrías estar pensando que obtendremos las versiones anterior y nueva de la propiedad datos
. Ahora mira el elemento. ¿Ves otras propiedades en él además de onupdate
? De hecho no hay y esto es un problema. El onupdate
para acceder a los datos, debemos registrar los datos como una propiedad directamente en el elemento donde está el gancho del ciclo de vida. Aquí está el componente con esa corrección:
function Lista({datos}) {
function mostrarCambio(element, propsViejas, propsNuevas) {
// Compara propsViejas con propsNuevas
}
// Pon los datos directamente en la etiqueta ul:
return (
<ul onupdate={mostrarCambio} datos={datos}>
{
datos.map(ítem => <li key={ítem.clave}>{ítem.valor}</li>)
}
</ul>
)
}
Este cambio sutil para exponener los datos al enganche update
significa que ahora tenemos acceso al estado anterior y actual de datos
. Con eso, podemos comparar propsViejas.datos
con propsNuevas.datos
para ver qué ha cambiado.
Ten cuidado de que siempre estás exponiendo las propiedades que necisitas en el miso elemento en el cual colocas onupdate
. Si no, los valores salirán no definidos (undefined).
En el ejemplo siguiente mostramos cómo usar onupate
para mostrar un mensaje de las diferencias entre el
valor de cuenta mientras va aumentando o disminuyendo. Por usar propsViejas y propsNuevas, podemos ver cómo el valor
cambia y entonces mostra esa diferencia en la consola.
See the Pen @composi/core - ejemplo de actualización by Robert Biggs (@rbiggs) on CodePen.
Es importante saber cuándo se debe de usar onupdate. El caso de uso para ello es muy limitado. Es útil si deseas ver cómo una propiedad ha cambiado. Nunca hay que utilizarlo para cambiar datos, ya que eso activaría otra actualización y te pondría en un bucle infinito. Puede usarlo para activar una animación. Durante la actualización, agregue una clase que cause la animación, y luego elimine la clase. También se puede usar onupdate para poner focus en un element de form, como un input de texto, etc.
onunmount
A veces, vas a querer saber cuando se está eliminando un componente del DOM para poder hacer algo. Tal vez necesites realizar una limpieza de ambiente o desencadenar algún otro evento o función. onunmount
te permite hacer eso. De hecho, onunmount
le permite interceptar el proceso de desmontaje y demorarlo hasta que hayas terminado con lo que sea que estás haciendo. Esto es ideal para situaciones en las que deseas hacer una animación cuando se elimina un ítem de una lista. Haremos una lista simple que usa onunmout
para animar el ítem de lista antes de eliminarlo. Para esto, omitiremos la parte que realmente elimina un ítem de lista ya que ya cubrimos eso en el ejemplo anterior para la delegación de eventos.
onunmount
expects that its callback with handle a done()
function. Specifically, onunmount
gets passed two arguments: the element being deleted, and a done
callback to invoke when you are done. If you fail to provide a done()
callback in your code or forget to invoke at the end of your code, the element will not be removed from the DOM, which could result in really unexpected results as the list data is mutated.
onunmount
espera que su callback va tratar con una función done()
. Específicamente, onunmount
pasa dos argumentos: el elemento que se está eliminando y el callback done
para invocar cuando haya terminado. Si no proporcionas un callback done()
en su código u olvidas invocarlo al final del código en esa función, el elemento no se eliminará del DOM, lo que podría causar resultados realmente inesperados mientras se cambian los datos de aquella lista.
En el ejemplo próximo usamos onunmount
para implementar una animación de keyframe antes de que el ítem de lista sea eliminado. También usamos onmount
en los ítemes de lista para hacer la animación de los ítemes nuevos mientras se trasladan en la vista.
See the Pen @composi/core - Ciclo de Vida-onunmount by Robert Biggs (@rbiggs) on CodePen.
Argumentos para Ciclos de Vida
Los enganches de ciclo de vida reciben sus argumentos automáticamente, así pues puedes utilizar sus gestores sin argumento en los eventos en línea. Cada enganche de ciclo de vida espera argumentos diferentes, pero puedes indicarlos en su gestor en el evento en línea:
function Lista() {
function init(base) {
// Haz algo con el elemento base del componente.
base.querySelector('input').focus()
}
function mostrarCambio(element, propsViejas, propsNuevas) {
// El elemente en el cual se ubica el evento, en este caso, la etiqueta ul.
// Compara los valores de propsViejas con los nuevos.
if (propsNuevas.data.length > propsViejas.data.length) {
console.log('Se agregó un ítem a la lista.')
} else {
console.log('Se eliminó un ítem de la lista.')
}
}
function gestionarDesmonte(element, done) {
// Haz algo con el elemento base del componente.
// Entonces desencadena la animación de eliminación.
element.classList.add('deleting')
// Then let the component unmount.
// Since we've set the animation to last 3 seconds,
// we need to delay the unmounting for 3 seconds:
// Entonces deja que el componente desmonte.
// Pueste que hicimos que la animación dure tres segundos,
// tenemos que demorar el desmontar por tres segundos.
setTimeout(() => {
done()
}, 3000)
}
return (
<ul onmount={init} onupdate={mostrarCambio} onunmount={gestionarDesmonte} data={data}></ul>
)
}
Lo que hay que tener en cuenta con onunmount
es que causa que el desmontar sea asincrónico. Aunque el algoritmo de parche ha identificado una condición que requiere que el elemento se elimine del DOM, espera hasta que invocas done()
en el gestor para terminar la eliminación del elemento.