Photo by elCarito on Unsplash

Hablemos sobre React Suspense

Brian Cortes
Monoku
Published in
4 min readNov 28, 2019

--

Antes de empezar a jugar con todos las mejoras que nos trae React a partir de la versión 16.6, tenemos que aclarar que todas las nuevas APIs que a continuación vamos a mostrar, aún no están en un versión estable de React.

La propia documentación no recomienda implementar estas en producción, ya que pueden estar sujetas a muchos cambios, pero eso no quiere decir que no podamos probar y divertirnos un poco con ellas; la ventaja de aprender jugando es que cuando todos estas mejoras ya estén disponibles, nuestra curva de aprendizaje se reduce considerablemente.

Todo nace de la necesidad de tener un mayor control de funciones asíncronas o promesas llamadas desde un componente en React, ya sean de tipo Clase o utilizando Hooks, el ejemplo más común donde podemos ver su poder, es realizando un Fetch para obtener datos externos, pero también se puede usar para la carga de archivos, imágenes o scripts.

React Suspense no es una librería para obtener datos, es un conjunto de APIs que crean un mecanismo, para suspender el render y esperar cuando la data esté lista o no, dando una mejor experiencia a nuestros usuarios, minimizando errores de manejo estados, por ejemplo con un Loader, limpiando código repetitivo y evitando un montón de condicionales en el render.

Empecemos 💪🏽

Primero veamos un ejemplo que comúnmente realizamos cuando queremos traer data a un componente, normalmente definimos dos estados:

state = {
loading: true,
data: null,
}
///// render
const {
loading, error, data
} = this.state;
return loading ? (
<p>Loading...</p>
) : error ? (
<p>Error: {error}</p>
) : (
<p>Data loaded</p>
);

Esto lo repetimos una y otra vez, lo cual esta bien 🤔 pero puede ser propenso a errores si se manejan de manera inadecuada y se puede convertir en un caos manejando múltiples estados al mismo tiempo, un ejemplo es tener componentes anidados y que cada uno obtenga su propia data:

<Pokemon>
<PokemonDetail/>
<PokemonInfo/>
<PokemonEvolutions/>
<PokemonMoves>
<MoveAilments/>
<MoveBattleStyles/>
<MoveCategories/>
<MoveLearnMethods/>
</PokemonMoves>
</Pokemon>

El problema es cómo administramos la carga de cada componente y sus respectivos request.

Veamos posibles soluciones:

  • Cada componente se encargará de hacer su petición (request) y manejar su estado de carga independientemente.
  • Manejar un estado global de todos los componentes, para ello necesitamos un contenedor que maneje cada uno de los llamados y por medio props se envie la data a cada componente.

Este es el dilema que tenemos a diario y no tenemos una solución perfecta para ello, ya que según las necesidades y complejidad de la aplicación, puedes optar por cualquiera de ellas; el Core Team de React detectado este patrón y ha decido hacer algo al respecto con el fin de mejorar los siguientes aspectos:

✏️ Manejo de estados en la carga de un componente.

🎉 Reducción de Código Repetitivo.

🎈Reducción de condicionales en nuestro Render

Para solventar esto React está implementando un componente llamado Suspense, que hace el trabajo tedioso por nosotros, su lógica es muy simple, este recibe un prop llamado fallback el cual devuelve un componente que será renderizado hasta que nuestra data esté lista, pero al mismo tiempo recibe por children el componente que queremos mostrar, en el que se suspenderá su render hasta que se cumplan todas las promesas requeridas, un ejemplo de su uso sería el siguiente:

<Suspense fallback={<Spinner />}>
<ProfilePage />
</Suspense>

Ahora para utilizar Suspense se requiere que las librerías de obtención de datos le den soporte, si vas a utilizarlo con axios, fetch u otra librería asegúrate que estas lo tengan, ya que Suspense necesita una capa extra para saber el estado de las promesas.

Actualmente Relay por parte de Facebook ha proporcionado un soporte claro y están utilizando Suspense en producción; dan_abramov creó una función que se encarga de administrar las promesas y enviarlas en su respectivo estado, para efectos de práctica y simular el soporte que Relay implementó.

Con este Script podemos darle soporte a Suspense pero sólo es para efectos de prueba. Veamos cómo podemos hacer peticiones anidadas con Suspense:

<Suspense fallback={<h1>Cargando pokemon...</h1>}>
<Pokemon />
<Suspense fallback={<h2>Cargando Detalles...</h2>}>
<PokemonDetails />
</Suspense>
</Suspense>

Si te das cuenta es muy simple de usar y el código es legible.

Ahora te preguntarás qué tipo de lógica tenemos en los componentes Pokemon o PokémonDetails, veamos 👀:

import React from "react";
import { fetchData } from "../Api/pokemon";
const resource = fetchData();const Pokemon = () => {
console.log("rendering Pokemon component");
return (
<div>
<h1>Que pokemon es ?</h1>
<img
width="200px"
src={resource.pokemon.read().sprites.front_default}
alt="Charizard"
/>
</div>
);
};

El componente Pokémon llama al método read, el cual es el encargado de enviar las promesas y devolvernos la data, en este caso obtendremos la imagen de nuestro Pokémon.

Suspense no retorna lo que tengamos en la función render, hasta que se resuelvan todas las promesas que este necesite, nos evitamos hacer condicionales extras y tener estados internos, lo cual es una maravilla.

Pruébalo tú mismo:

En el demo se realizó un delay en la respuesta del API de Pokémon, con el fin de ver cómo Suspense realiza su magia y ver cómo administra el render de cada componente.

Conclusión

React Suspense es algo que los desarrolladores de React necesitaban desde hace mucho tiempo. Me encantaría ver un gran auge de soporte a librerías de obtención de datos y espero en un futuro no tan lejano poder usarla en producción, ya que aumentará significativamente la experiencia de usuario en nuestras aplicaciones y disminuirá los errores.

Cualquier duda o comentario puedes escribirme directamente a Twitter 🤟🏽

¡Hola! 👋🏼

¿Ya conoces Monoku? Somos una organización latinoamericana que crea, diseña y desarrolla productos digitales con el objetivo de conectar e impactar de manera positiva la vida de las personas. Te invitamos a que nos conozcas más visitando http://monoku.com y seguirnos en nuestras redes sociales Facebook, Instagram ,Twitter y Spectrum.

--

--

Brian Cortes
Monoku
Writer for

Front-End Developer 🔥I’m a computer engineer and I love coding 🤠