Revisando el uso de los ganchos del ciclo de vida de componentes de React en anticipación de la representación asíncrona

Si ha examinado la documentación, o ha estado atento a los consejos del equipo principal de React, probablemente haya leído que no debe manejar suscripciones o efectos secundarios en el constructor o componentWillMount.

Si bien el consejo es claro, el razonamiento detrás de estas instrucciones no ha sido muy elaborado, aunque no sin razón. La breve explicación es que los detalles de implementación del renderizado asíncrono de Fiber, que motivan estas instrucciones, no están completamente resueltos.

Debido a que el renderizado asíncrono de Fiber aún no está habilitado, ignorar algo de la sabiduría sobre el uso del ciclo de vida podría no haberte mordido todavía. En el futuro, esto podría cambiar, y eso es lo que vamos a explorar en este artículo.

Aclaración: ¿está lista la fibra?

Si el renderizado asíncrono de Fiber no está listo, es posible que se pregunte si el equipo le vendió una cuenta regresiva falsificada. Tenga la seguridad de que este no es el caso. El nuevo motor de Fiber, o más específicamente el proceso de reconciliación, se ha puesto en funcionamiento con React v16. Dicho esto, todavía no podemos cambiar los engranajes del renderizado síncrono a los renderizados priorizados.

¿Cómo se verá afectado el uso de los ciclos de vida?

En conclusión, no lo sabemos hasta que la representación asíncrona esté establecida en piedra. De lo contrario, el equipo React habría dicho lo mismo. Pero podemos sacar algunas conclusiones seguras sobre el manejo de suscripciones y efectos secundarios. Y eso es lo que exploraremos.

En aras de la simplicidad, aquí hay un ejemplo de suscripción a una lista de consultas de medios en el constructor, que actualmente no nos causará problemas:

Antes de habilitar el renderizado asíncrono, no tenemos ningún problema porque podemos hacer las siguientes garantías sobre el componente:

  1. El constructor será seguido sincrónicamente por componentWillMount, si optamos por usarlo, y luego renderizar. Es importante destacar que no seremos interrumpidos antes de renderizar. Debido a esto, podemos garantizar aún más ...
  2. Si el componente se desmonta en el futuro, componentWillUnmount limpiará el detector de eventos (suscripción) de antemano. Esto significa que la ventana no retendrá una referencia al método handleMediaEvent del componente a través de la lista de consultas de medios, permitiendo así que el componente desmontado se recolecte basura y, por lo tanto, evite una pérdida de memoria. No limpiar esto una vez no sería un gran problema, pero volver a montar un componente y agregar más oyentes podría causar problemas durante la vida útil de la aplicación.
Hay una advertencia: límites de error. Tocaré eso en un momento.

Entonces, ¿qué cambia con el renderizado asíncrono?

Para ir directo al grano: muchos de los métodos del ciclo de vida de los componentes de su clase pueden activarse más de una vez. Esto se debe a que el proceso de reconciliación de Fiber permite que React produzca el trabajo que está haciendo. Permitir que el hilo principal maneje algo que debe mostrarse con urgencia como animación. Esto puede implicar descartar el trabajo ya completado, que puede incluir invocaciones del constructor, componentWillMount, render, componentWillUpdate y componentWillReceiveProps.

Pero, componentDidUpdate y componentDidMount solo se invocan después de que React ha eliminado los cambios en su entorno host. Evitando así estos problemas. La limpieza o "desmontaje" en componentWillUnmount debería reflejar la configuración en componentDidMount. Ayudar a garantizar que no se pueda llamar a este enlace no será problemático.

Por lo tanto, necesitamos manejar suscripciones y efectos secundarios en componentDidMount. Los efectos secundarios que tienen lugar en el constructor y componentWillMount a menudo incluyen solicitudes de red. Son especialmente problemáticos llamar varias veces cuando provocan mutaciones en los almacenes de datos de back-end de nuestra aplicación.

Una última nota.

Al igual que yo, es posible que haya asumido que el primer render de React está garantizado para ser siempre sincrónico. ¡Pero este no es necesariamente el caso!

Brian Vaughn (que está en el equipo principal de React) me informó que la intención actual es que el primer renderizado se sincronice de forma predeterminada, con la opción asíncrona opcional. Agregó que un primer renderizado de baja prioridad podría ser valioso si, por ejemplo, el contenedor host de React aún no está listo. Obviamente, esto es más aplicable cuando su cuerpo HTML consta de más de un div para que React represente.

Para obtener una lista de verificación visual de lo que es seguro realizar y dónde, vea la esencia de Brian.

¿Para qué sirve componentWillMount?

El caso de uso es muy estrecho. Los desarrolladores a menudo citan dos rasgos deseables de componentWillMount. Son:

  1. Se puede llamar a setState desde componentWillMount, a diferencia del constructor.
  2. Un setState en componentWillMount no provocará dos renders si se produce de forma sincrónica, antes del render, a diferencia de componentDidMount.

Del mismo modo, la razón por la que componentWillMount se mantuvo originalmente en la base de código, como explica Sebastian Markbåge en una propuesta para desaprobar componentWillMount, fue para manejar un efecto secundario que podría ser sincrónico (si un caché local contenía los datos deseados) o asincrónico en la alternativa. Hoy, como lo transmite su bloque de código de demostración, getInitialState, los constructores de clase es6 y los inicializadores de propiedades es7 se adaptan a este propósito.

Dicho todo esto, una solicitud GET de solo lectura iniciada desde componentWillMount puede ser útil. En un dispositivo de procesamiento lento, por ejemplo, un dispositivo móvil promedio, es posible ahorrar unos pocos cientos de milisegundos iniciando la solicitud aquí en lugar de componentDidMount. Por supuesto, dicha solicitud debe ser idempotente / de solo lectura, ya que puede activarse más de una vez.

Cuando se procesa en el servidor, componentWillMount sigue siendo el único método de ciclo de vida llamado distinto del constructor, por lo que es posible que haya algunos casos de uso allí. Al no haber intentado la representación del lado del servidor, no puedo dar más detalles sobre el tema.

Entonces, ¿estas advertencias solo son relevantes una vez que la representación asincrónica está activa?

Como Brian me señaló, no del todo. ¡Los límites de error, que se activaron con React v16, también pueden dar como resultado la invocación de componentWillMount y componentWillUpdate sin un componentDidMount y componentDidUpdate correspondiente!

¿Hay otros cambios a tener en cuenta?

React inició recientemente un proceso RFC (Solicitud de comentarios), que permite a la comunidad en general discutir ideas. Dos de los primeros RFC son de miembros del equipo central de React, que discuten cambios potenciales significativos.

  1. Andrew Clark envió un RFC sobre los cambios en la API de contexto. Con suerte, esto aliviará algunas de las dificultades para moverse debería debería actualizarse cuando se intenta transmitir el estado del árbol de componentes. El RFC está aquí.
  2. Brian envió un RFC para ganchos de ciclo de vida estáticos asíncronos. Esto implica principalmente la depreciación gradual de componentWillMount, componentWillUpdate y componentWillReceieveProps. Se proponen dos nuevos ganchos estáticos: prefetch y deriveStateFromProps. Puede leer más sobre la propuesta aquí, y el RFC aquí. Esperemos que este artículo le haya proporcionado una buena idea de por qué se proponen estos cambios :).
  3. En la propuesta antes mencionada, Brian también se burló de un próximo RFC para un nuevo enlace SSR: componentDidServerRender, tomando el lugar de componentWillMount en el servidor.

¡Tenga en cuenta que estas son propuestas iniciales!

Sobre el Autor

¡Soy un desarrollador australiano ubicado en Adelaida, apasionado por el desarrollo tanto front-end como back-end con JavaScript! Recientemente publiqué mi primera biblioteca de código abierto para React: React-MQL-Manager. ¡Aquí hay una demostración simple, que se integra con React Router v4 para un enrutamiento receptivo!

Actualmente estoy buscando mi primera posición de front-end o full-stack. Puede contactarme por correo electrónico o saludarme en Twitter: @awebofbrown.

Gracias especiales

Un enorme agradecimiento a Brian Vaughn, del equipo central de React, por tomarse el tiempo de leer un borrador del artículo y hacer sugerencias y correcciones. Además de trabajar en React, Brian es autor de algunas excelentes bibliotecas de código abierto como React-Virtualized y JS-Search, además de ayudar a responder preguntas de la comunidad en foros como StackOverflow.