React — Ciclo de vida de un componente, propiedades y estado

Mauricio Garcia
13 min readJul 27, 2020

--

Temario

  • Ciclo de vida de un componente (Montaje, Actualización, Desmontaje)
  • Métodos de ciclo de vida (Montaje — constructor, render, componentDidMount; Actualización — render, componentDidUpdate; Desmontaje — componentWillUnmount )
  • Propiedades (props) y Estado (state) en el ciclo de vida (Montaje, Actualización, Desmontaje)
  • Propiedades de clase y de instancia
  • El método this.setState()

i. Ciclo de vida de un componente

En la story pasada (React — Primeros pasos… [ref]), vimos que existen dos formas de crear componentes (funcionales y de clases), en la mayoría de los ejemplos nos enfocamos al funcional, ahora veremos el de clase.

Cuando creamos un componente de clase, tenemos la ventaja, que al extenderlo de React.Component nos va a proporcionar más métodos y propiedades, que van a mejorar de manera exponencial el componente.

Vamos a crear un componente básico de clase:

Para entender mejor el ejemplo, es necesario saber qué React.Component, tiene tres ciclos de vida:

a — Montaje

Cuando se crea una instancia de un componente y se inserta en el DOM

b — Actualización

Cuando sufre algún cambio las propiedades (props) o el estado (state) del componente.

c — Desmontaje

Cuando el componente se elimina del DOM.

ii. Métodos de ciclo de vida

A su vez cada ciclo de vida, nos va a proporcionar diferentes métodos de ciclo de vida para el componente, dependiendo en qué fase se encuentre, vamos a poder utilizar:

a — Montaje

— constructor(props):

  • El constructor es llamado antes de ser montado el componente en el DOM.
  • Es OBLIGATORIO pasar el argumento props.
  • Al ser extendiendo React.Component, es OBLIGATORIO ejecutar el método super(props) pasandole el argumento props, antes que cualquier otra instrucción, ya que de no ser así, puede ocasionar errores.
  • Es útil para inicializar el estado local (this.state).
  • Es útil para enlazar manejadores de eventos a una instancia.

— render():

  • El único método obligatorio en un componente de clase.
  • Puede retornar un elemento en React a través de JSX (Ej. <div />, <MyComponent />, y es renderizado como un nodo DOM.
  • Puede retornar fragmentos de elementos (útil cuando creamos tablas)
  • Puede retornar el renderizado de un hijo como otro nodo DOM, llamados portales (es útil para sacar sacarlo de un contenedor, ej. modales, tooltips).
  • Puede retornar datos tipo String (cadenas de texto o números), que son renderizados como nodos de texto en el DOM.
  • Se recomienda que la función sea pura, esto quiere decir que no modifique variables, propiedades o estado del componente, debe devolver siempre el mismo resultado cada vez que se invoca.

— componentDidMount():

  • Se invoca inmediatamente después que el componente se monte.
  • Carga de datos de alguna API.
  • Podemos modificar el estado (setState()), donde activará un renderizado extra; hay que tener cuidado de cómo ocuparlo, ya que puede afectar al rendimiento de la aplicación, es útil cuando debemos saber propiedades de algún nodo DOM (tamaño, posición) como un modal o tooltip.
  • Para hacer suscripciones (no olvides darla de baja en componentWillUnmount).

b — Actualización

— render():

  • Todas las opciones que tiene cuando se monta.
  • Cuando sufre algún cambio el componente y se necesita renderizar el componente (cuando se cambia el estado en componentDidMount()).

— componentDidUpdate(prevProps, prevState):

  • Se invoca inmediatamente después de que la actualización ocurra.
  • Este método NO es llamado en el renderizado inicial.
  • Es útil para para hacer solicitudes API, siempre y cuando se compare las propiedades (this.props) con el argumento prevProps, esto con el fin de que si no hay cambios, no afecte.
  • Podemos modificar el estado (setState), pero, al igual que el punto anterior se debe comparar el actual this.state con el anterior prevState, ya que de lo contrario puedes generar un bucle infinito.
  • Es útil cuando queremos realizar un efecto secundario (ej. obtención de datos o animaciones) en una respuesta debido a un cambio en los props.

c — Desmontaje

— componentWillUnmount():

  • Se invoca inmediatamente antes de desmontar y destruir el componente.
  • Es útil para realizar limpieza de tareas (temporizadores, solicitudes de red, suscripciones)
  • PROHIBIDO modificar el estado (setState), ya que el componente se vuelve a renderizar.
  • Una vez que una instancia de componente sea desmontada, NUNCA será montada de nuevo, si volvemos a montar el componente va a ser una NUEVA instancia de él.

Veamos un ejemplo con todos los métodos de ciclo de vida:

Nota: Para verlo en acción, debes darle click al botón, y revisar en consola como va ejecutando los diferentes métodos de ciclo de vida, y para ejecutar el método de desmontaje, debes darle click de nuevo al botón y revisar en consola. Si le das click de nuevo al botón, se ejecutará una NUEVA instancia del componente.

En el ejemplo anterior hay código que quizás puede ser extraño (ej. el evento del botón), por ahora no nos preocupemos por eso, más adelante veremos con detalle…por ahora solo enfoquémonos en los métodos de ciclo de vida.

En la animación de arriba podemos ver lo siguiente:

  • Cuando inicia nuestra aplicación <App />, NO hay nada en consola, ya que el componente <Welcome /> NO ha sido instanciado.
  • Cuando se instancia el componente, muestra en consola los diferentes métodos de ciclo de vida por los que pasa.

Podemos observar que pasa dos veces por render, ya que, la primera vez es cuando se monta el componente, y el segundo es cuando componentDidMount actualiza el estado (simulamos recibir datos).

  • Cuando le damos click de nuevo al botón, para desmontar el componente, es cuando muestra en consola el último método que nos hacía falta:

iii. Propiedades (props) y Estado (state) en el ciclo de vida (Montaje, Actualización, Desmontaje)

Si hemos puesto atención a los conceptos y ejemplos de arriba, he mencionado mucho las palabras propiedades (props) y estado (state) que tiene un componente; estos conceptos, tienen una función específica dentro del componente y al igual que los métodos, dependiendo en el ciclo de vida en el que se encuentren, son los usos que podemos darle.

Vamos a complementar la imagen:

— this.props

  • Son los atributos que se envían desde el elemento.
  • Son solo de LECTURA, por lo que NUNCA deben modificarse
  • Está considerado dentro del grupo de propiedades de instancia de un componente

— this.state

  • Es un objeto de propiedades (key/value), que van a ser privadas y que son controladas COMPLETAMENTE por el componente
  • Se ocupan cuando queremos “observar” alguna propiedad y que afecte el componente
  • El único lugar para crearlo y modificarlo directamente como this.state es el método constructor, para todos los demás usar this.setState()
  • NO se recomienda agregar un estado, si no va a cambiar o cuando no queremos que afecte al nodo DOM.
  • Para el manejo de propiedades internasnormales” es mejor agregarlas dentro de this (this.anyVar)
  • Está considerado dentro del grupo de propiedades de instancia de un componente

— this.setState({key: value})

  • Método que vamos a ocupar cuando queremos actualizar un valor de una propiedad del objeto estado (this.state).
  • Para cambiar una propiedad NUNCA usar directamente this.state
  • Cuando se actualiza un estado, React vuelve a procesar el componente y sus elementos.
  • Lo ocupamos para actualizar la interfaz de usuario (ej. respuesta de un manejador de evento, respuesta de una API, validación)
  • Es importante saber que, internamente React puede retrasar la actualización del componente, esperando a que otros componentes puedan ser afectados, por lo que NO garantiza que los cambios de estado sean inmediatos.
  • Para garantizar el cambio inmediato, se recomienda hacerlo en el método componentDidUpdate() o setState con un callback (veremos un ejemplo más abajo)

Vamos a ver cómo se comporta, dependiendo del ciclo de vida y de los métodos de ciclo de vida.

a — Montaje

— constructor(props):

  • props — Es el único método donde se pasa por argumentos, y es obligatorio mandarlo al método super (super(props)) y sólo es de lectura
  • this.state — Es el único método donde debemos inicializar el estado local del componente (this.state = {}). ¡Evita copiar los props en el estado! (this.state = { color: props.color };), podemos usar el valor directamente [ref].
  • this.setState() — NO debemos utilizar setState() en este método, en su lugar, asignar directamente el estado inicial al this.state.

— render():

  • props — Sólo es de lectura
  • this.state — Sólo es de lectura
  • this.setState() — Recordemos que la filosofía de React es que el render() sea una función pura, por lo que no se recomienda usar este método aquí, si queremos realizar cambios, es mejor en componentDidMount()

— componentDidMount():

  • props — Sólo es de lectura
  • this.state — Sólo es de lectura
  • this.setState() — Podemos modificar el estado con este método, solo que es importante saber que va realizar un renderizado extra (si cambia el valor), esto quiere decir que el método render se va a invocar dos veces. Utiliza este patrón con cuidado porque puede causar problemas de rendimiento.

b — Actualización

— render():

  • Aplican las mismas reglas que cuando se monta el componente.

— componentDidUpdate():

  • props — Sólo es de lectura
  • this.state — Sólo es de lectura
  • this.setState() — Podemos modificar el estado con este método, es importante comparar el actual this.state con el anterior prevState, ya que de lo contrario puedes generar un bucle infinito, y no olvidemos que va realizar un renderizado extra (si cambia el valor), esto quiere decir que el método render se va a invocar dos veces.

c — Desmontaje

— componentWillUnmount():

  • props — Sólo es de lectura
  • this.state — Sólo es de lectura
  • this.setState() — NO UTILIZAR

iv. Propiedades de clase y de instancia

En React, un componente de clase, tiene dos grupos de propiedades

a— Propiedades de clase

— defaultProps

Son una propiedad predeterminada dentro del componente de clase.

Imaginemos que tenemos un componente llamado Welcome, donde esperamos que nos envíen por medio del atributo name un valor:

Lo que queremos es que cuando NO nos mandan el atributo name, por default poner Stranger, caso contrario, poner el valor que nos mandan, algo así:

Sabemos que las propiedades (this.props), NO DEBEN SER MODIFICADAS, por lo que no debemos hacer alguna validación para reasignar el valor…Por fortuna los desarrolladores de React pensaron en eso, creando la propiedad defaultProps, veamos su sintaxis:

Entonces, para nuestro ejemplo, quedaría de la siguiente manera:

Ahora sí, veamos nuestro ejemplo completo:

Importante: Tener cuidado con el valor null, ya que si toma el valor, por lo que en nuestro ejemplo se verávacía” la propiedad

— displayName

Antes de ver esta propiedad, si están usando Chrome, les recomiendo instalar la extensión React Developer Tools[ref]. Nos va a servir bastante para depurar, revisar o modificar los componentes desde consola.

Esta propiedad es muy útil cuando creamos componentes de orden superior (veremos más adelante) o cuando queremos ponerle un nombre explícitamente a un componente (muy útil al momento de depurar en consola)

Si nosotros vemos en consola nuestro componente (sin el cambio), veremos lo siguiente:

En la animación podemos observar que aparece el nombre de nuestro componente (como debe ser), ahora, vamos a ponerle el nombre de yoSoyUnComponenteÚnicoYDiferente

Veamos nuestro ejemplo completo:

Si lo revisamos en consola, podemos observar que el nombre ha cambiado:

Es importante entender que nuestro componente sigue siendo Welcome, pero el nombre para depuración es el que le asignamos.

b— Propiedades de instancia

Las propiedades de instancia realmente ya las conocemos…

— props

Son las propiedades que fueron definidas como atributos en el componente y se puede acceder a ellas en modo consulta es this.props

— estado (state)

Son las propiedades con datos específicos para el componente, que pueden cambiar con el tiempo, y que además van a afectar el nodo DOM. Se inicializan en el método constructor, y para modificarlas se usa el método setState() y para acceder a ellas en modo consulta es this.state

v. El método this.setState()

En el capítulo pasado comprendimos que podemos manejar el estado del componente, inicializando en el método constructor (this.state = {}), y actualizando con el método setState (this.setState({key: ‘newValue’});)

this.state: Es un objeto de propiedades (key/value), que van a ser privadas y que son controladas COMPLETAMENTE por el componente.

Ejemplo 1:

Imaginemos que tenemos tenemos el siguiente componente:

La idea es que el componente va a consumir una API, y dependiendo del resultado, vamos a cambiar el color; vamos a hacer paso a paso el componente:

  • Primero vamos a crear un componente llamado Welcome
  • Creamos una hoja de estilos (style.css), la importamos en el index.html y agregamos lo siguiente:
  • El siguiente paso es inicializar el estado, creamos el método construct, para agregar el estado classColor.
  • En el componente agregamos el atributo className y le asignamos el estado creado.
  • Ahora vamos a simular un llamado a una API, donde dependiendo lo que nos regrese, vamos a cambiar el color, entonces, vamos a utilizar el método componentDidMount:

Cuando se ha montado el componente, React ejecuta la función componentDidMount, nosotros simulamos llamar a una API, ejecutando el método this._getDataAPI(), dentro de este método, lo que hacemos es poner un setTimeout[ref] de 4 segundos; donde, vamos a generar un número random (0,1), para cambiar el estado de classColor.

Cuando setState hace cambios al estado del componente, le dice a React que debe volver a procesar el componente con el estado actualizado.

Lo interesante de React, como ya lo hemos venido mencionado, es el cambio necesario del nodo DOM, veamos la siguiente animación:

Podemos observar que SOLO actualiza el atributo class y NO todo el nodo DOM, por lo que el rendimiento de nuestra aplicación es óptima.

No olvidemos: Para un mejor rendimiento percibido, React puede retrasarse, y después actualizar varios componentes en una sola pasada. React NO garantiza que los cambios de estado se apliquen de inmediato.

Lo genial de utilizar el estado, es que podemos tener diferentes variables independientes, y SOLO va a AFECTAR a la que estamos actualizando:

Hemos agregado un nuevo estado llamado name, cuando nosotros cambiamos el estado classColor, podemos observar que al estado name no le afecta, por lo que todos los estados que agregamos se comportan de manera independiente (lectura y modificación).

No olvidemos: SIEMPRE que usamos setState(), va a re-renderizar el componente

Veamos nuestro ejemplo completo (puedes darle run, para volver a ejecutar la aplicación y quizás ver el otro resultado):

Ejemplo 2:

¿Recuerdan el elemento, donde le decíamos cuantos segundos lleva en nuestra aplicación?

Lo convertiremos en un componente de clase, y veremos cómo usar el setState cuando hay cambios asíncronos.

  • Primero, vamos a crear el componente Timer:

Hemos creado un estado llamado seconds, que mostramos en el componente, hasta aquí no hace nada especial, debe verse algo así:

  • El siguiente paso, es de que cuando se monte el componente (componentDidMount), cambie el estado seconds a 1, y se vea reflejado.

Cambiemos el setTimeout por el setInterval[ref], para que cada segundo se actualice el estado seconds

Parece que funciona de manera normal y correcta, pero, recordemos que setState no siempre va a actualizar inmediatamente el componente, ya que para un mejor rendimiento, React puede procesar los cambios por lotes o diferir la actualización. Por eso se recomienda usar setState como un updater, esto quiere decir que setState deberá establecer el estado mediante una función (callback), veamos la sintaxis:

state y props recibidos por la función, están garantizados de estar actualizados.

  • Hagamos el cambio en nuestro ejemplo:

Da la impresión de que no ha hecho ningún cambio, pero realmente SI, que es el garantizar que el estado y propiedades van a ser las actualizadas.

  • Y por último, no debemos olvidar que al momento de desmontar el componente, debemos de eliminar el temporizador

Veamos nuestro ejemplo completo:

En la siguiente entrega vamos a ver React —Manejadores de Eventos

La entrega pasada vimos React — Primeros pasos…

--

--

No responses yet