Qué es el ciclo de vida y cómo implementar métodos dentro del ciclo de vida, para qué necesitamos usarlo.
El ciclo de vida no es más que una serie de estados por los cuales pasa todo componente a lo largo de su existencia. Esos estados tienen correspondencia en diversos métodos, que nosotros podemos implementar para realizar acciones cuando se van produciendo.
En React es fundamental el ciclo de vida, porque hay determinadas acciones que debemos necesariamente realizar en el momento correcto de ese ciclo. Ese es el motivo por el que hay que aprenderse muy bien cuáles son las distintas etapas por las que pasa la ejecución de un componente React. No es un tema trivial y tiene diversos matices. Veremos una introducción en este artículo y pondremos ejemplos.
Antes de comenzar cabe decir que esto es algo específico de los componentes con estado, ya que los componentes sin estado tienen apenas un método que se usará para renderizar el componente y React no controlará su ciclo de vida a través de los métodos que veremos a continuación. Montaje, actualización y desmontaje.
Estas son las tres clasificaciones de los estados dentro de un ciclo de vida del componente.
- El montaje se produce la primera vez que un componente va a generarse, incluyéndose en el DOM.
- La actualización se produce cuando el componente ya generado se está actualizando.
- El desmontaje se produce cuando el componente se elimina del DOM.
Además, dependiendo del estado actual de un componente y lo que está ocurriendo con él, se producirán grupos diferentes de etapas del ciclo de vida. En la siguiente imagen puedes ver un resumen de esta diferenciación. Observarás que en el primer renderizado de un componente se pasa por etapas del ciclo de vida diferentes de las que se pasa cuando se produce un cambio en sus propiedades o un cambio en el estado, o su desmontaje.
La secuencia de ejecución de las etapas del ciclo de vida se da de arriba hacia abajo. Los elementos marcados con un asterisco naranja no son métodos del ciclo de vida propiamente dicho, pero sí que son etapas de ejecución de componentes y se producen en la secuencia descrita en la imagen.
Descripción de los métodos del ciclo de vida
Ahora vamos a describir las distintas etapas del ciclo de vida de los componentes y luego podremos ver ejemplos.
componentWillMount()
Este método del ciclo de vida es de tipo montaje. Se ejecuta justo antes del primer renderizado del componente. Si dentro de este método seteas el estado del componente con setState(), el primer renderizado mostrará ya el dato actualizado y sólo se renderizará una vez el componente.
componentDidMount()
Método de montaje, que solo se ejecuta en el lado del cliente. Se produce inmediatamente después del primer renderizado. Una vez se invoca este método ya están disponibles los elementos asociados al componente en el DOM. Si el elemento tiene otros componentes hijo, se tiene certeza que éstos se han inicializado también y han pasado por los correspondientes componentDidMount. Si se tiene que realizar llamadas Ajax, setIntervals, y cosas similares, éste es el sitio adecuado.
componentWillReceiveProps(nextProps)
Método de actualización que se invoca cuando las propiedades se van a actualizar, aunque no en el primer renderizado del componente, así que no se invocará antes de inicializar las propiedades por primera vez. Tiene como particularidad que recibe el valor futuro del objeto de propiedades que se va a tener. El valor anterior es el que está todavía en el componente, pues este método se invocará antes de que esos cambios se hayan producido.
shouldComponentUpdate(nextProps, nextState)
Es un método de actualización y tiene una particularidad especial con respecto a otros métodos del ciclo de vida, que consiste en que debe devolver un valor boleano. Si devuelve verdadero quiere decir que el componente se debe renderizar de nuevo y si recibe falso quiere decir que el componente no se debe de renderizar de nuevo. Se invocará tanto cuando se producen cambios de propiedades o cambios de estado y es una oportunidad de comprobar si esos cambios deberían producir una actualización en la vista del componente. Por defecto (si no se definen) devuelve siempre true, para que los componentes se actualicen ante cualquier cambio de propiedades o estado. El motivo de su existencia es la optimización, puesto que el proceso de renderizado tiene un coste y podemos evitarlo si realmente no es necesario de realizar. Este método recibe dos parámetros con el conjunto de propiedades y estado futuro.
componentWillUpdate(nextProps, nextState)
Este método de actualización se invocará justo antes de que el componente vaya a actualizar su vista. Es indicado para tareas de preparación de esa inminente renderización causada por una actualización de propiedades o estado.
componentDidUpdate(prevProps, prevState)
Método de actualización que se ejecuta justamente después de haberse producido la actualización del componente. En este paso los cambios ya están trasladados al DOM del navegador, así que podríamos operar con el DOM para hacer nuevos cambios. Como parámetros en este caso recibes el valor anterior de las propiedades y el estado.
componentWillUnmount()
Este es el único método de desmontado y se ejecuta en el momento que el componente se va a retirar del DOM. Este método es muy importante, porque es el momento en el que se debe realizar una limpieza de cualquier cosa que tuviese el componente y que no deba seguir existiendo cuando se retire de la página. Por ejemplo, temporizadores o manejadores de eventos que se hayan generado sobre partes del navegador que no dependen de este componente.
Ejemplo de componente definiendo su ciclo de vida
Vamos a hacer un ejemplo muy básico sobre estos métodos, que simplemente lanza mensajes a la consola cuando ocurren cosas. El objetivo es que podamos apreciar el orden de ejecución de todos estos métodos del ciclo de vida.
El código de este componente con los métodos del ciclo de vida implementados lo encuentras a continuación:
import React from 'react'
export default class CicloVida extends React.Component {
constructor(...args) {
console.log('Ejecuto constructor', ...args)
super(...args)
this.state = {
estado: 'Inicializado en el constructor'
}
}
componentWillMount() {
console.log('Se ejecuta componentWillMount')
}
componentDidMount() {
console.log('Se ejecuta componentDidMount')
}
componentWillReceiveProps(nextProps) {
console.log('Se ejecuta componentWillReceiveProps con las propiedades futuras', nextProps)
}
shouldComponentUpdate(nextProps, nextState) {
console.log('Ejecutando shouldComponentUpdate. Próximas propiedades y estado: ', nextProps, nextState)
// debo devolver un boleano
return true
}
componentWillUpdate(nextProps, nextState) {
console.log('Ejecutando componentWillUpdate. Próximas propiedades y estado: ', nextProps, nextState)
}
componentDidUpdate(prevProps, prevState) {
console.log('Ejecutando componentDidUpdate. Anteriores propiedades y estado: ', prevProps, prevState)
}
componentWillUnmount() {
console.log('Se desmonta el componente...')
}
render() {
return (
<div>
<p>Componente del ciclo de vida</p>
<p>Estado: {this.state.estado}</p>
<p>Propiedad: {this.props.propiedad}</p>
</div>
)
}
}
CicloVida.defaultProps = {
propiedad: 'Valor por defecto definido para la propiedad'
}
Solo con que uses este componente tal cual podrás ver ya cómo se ejecutan los métodos del ciclo de vida relacionados con la parte del "primer renderizado" (mira la imagen anterior de este artículo).
Si quisieras poner en marcha otros métodos del ciclo de vida necesitarías hacer cosas como cambiar el estado del componente o sus propiedades. Como referencia te dejamos este otro código, en el que usamos el componente de CicloVida y cambiamos de manera dinámica una de sus propiedades.
import React from 'react'
import CicloVida from './index'
export default class UsarCicloVida extends React.Component {
constructor(...args) {
super(...args)
this.state = {
valorPropiedad: 'Test de valor de propiedad'
}
}
cambiarPropiedad() {
this.setState({
valorPropiedad: 'Otro valor'
})
}
render() {
return (
<div>
<button onClick={this.cambiarPropiedad.bind(this)}>Cambiar propiedad</button>
<CicloVida propiedad={this.state.valorPropiedad} />
</div>
)
}
}
Ese código hace uso del componente anterior. Lo podemos analizar parcialmente, puesto que todavía hay cosas aquí que no hemos llegado a tocar. Pero lo básico en que fijarse es en la propiedad bindeada. El estado del componente "UsarCicloVida" tiene un dato que se ha bindeado como valor de la propiedad del componente "CicloVida". Por otra parte tenemos un botón que cambia el estado, y por consiguiente el cambio de estado se traduce en una actualización de la propiedad del componente CicloVida, lo que desencadenará en la ejecución de los métodos del lifecycle relacionados con el cambio del valor de una propiedad.
Seguramente que, si tienes alguna experiencia con el desarrollo de librerías o frameworks que usen binding, podrás entender el ejemplo. Pero, como decíamos, son cosas que tenemos que ver con calma en futuros artículos de este manual.
De momento lo dejamos por aquí. Tienes bastante material para experimentar. Haremos otros ejemplos del ciclo de vida más interesantes en futuros artículos.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...