Estados de carga y error con useEffect en React

Resumen

Cuando construyes una aplicación real, mostrar propiedades cargadas no basta. El manejo de estados de carga y error en React marca la diferencia entre una app que confunde al usuario y una que le informa qué está pasando en cada momento. Si estás aprendiendo a leer datos con useEffect y quieres cuidar la experiencia de usuario, esto es para ti.

Hasta este punto solo teníamos dos escenarios visibles: cuando las propiedades ya estaban cargadas y cuando se estaban llamando. El problema es que nunca le avisábamos al usuario que espere, que estamos cargando o que hubo un error. El navegador tardaba cuatro segundos en mostrar las propiedades por un setTimeout seteado a mano, no por una API real, y el mensaje que aparecía no tenía relación con lo que realmente ocurría.

¿Por qué necesito estados de carga y error en mi aplicación?

Una aplicación seria contempla que los datos a veces no llegan. Pueden fallar por errores del servidor, por conjuntos vacíos o por datos incompletos. Sin estados que representen esas situaciones, tu usuario se queda mirando una pantalla que no le dice nada.

Por eso agregamos dos estados nuevos con useState [01:24]:

  • isLoading con valor inicial true, porque al iniciar siempre estamos cargando.
  • error con valor inicial null, porque al principio no hay ningún error.

Estos estados no cambian nada si solo los declaras. La magia aparece cuando los conectas con la lógica y con la interfaz.

¿Qué es el estado isLoading en React? Es una variable de estado que indica si los datos todavía se están cargando. Inicia en true y cambia a false cuando la carga termina, sea con éxito o con error.

¿Cómo uso try catch y finally dentro de useEffect?

Aquí viene lo interesante. En lugar de setear las propiedades directamente después del setTimeout, envolvemos la lógica en un bloque try, catch y finally [02:15].

La idea es sencilla:

  1. En el try intentamos setear las propiedades desde la API (setProperties(propertiesFromAPI)).
  2. En el catch capturamos cualquier error y seteamos el mensaje: "No pudimos cargar las propiedades".
  3. En el finally cambiamos isLoading a false, sin importar qué pasó.

Ese finally es clave: como isLoading inicia en true, necesitas apagarlo en cada cambio de estado para que la interfaz muestre el error o las propiedades según corresponda.

¿Por qué debo limpiar el timeout en useEffect?

Al usar setTimeout, lo encapsulamos en una constante llamada timerID. El propio editor recomienda devolver una función de limpieza dentro del useEffect que ejecute clearTimeout(timerID) [03:20].

Esto evita loops infinitos y que el navegador del usuario se quede sin recursos y colapse la aplicación. Sin importar si terminamos con propiedades o con error, el timeout siempre queda limpio.

¿Cómo muestro el estado de carga en la interfaz?

Con la lógica lista, todavía no se ve nada en pantalla. Necesitamos leer e interpretar esos estados dentro de la interfaz [05:10].

Lo primero es mostrar un mensaje de "Cargando propiedades" cuando isLoading es verdadero. Pero al refrescar notarás un detalle: sigue mostrando el resto porque el PropertyList se renderiza igual. Ese componente tiene el título de alojamientos disponibles y, si no recibe datos, muestra que no encontró alojamientos con esos criterios.

La solución es encapsular el PropertyList dentro de una validación con renderizado condicional. La condición dice: si no está cargando y no tiene error, renderiza el PropertyList [06:05].

Así el flujo queda limpio:

  • Mientras isLoading es true, aparece "Cargando propiedades".
  • Cuando termina, aparecen las propiedades.

Pasados los cuatro segundos, tus propiedades se muestran. Ya con esto la experiencia de usuario mejora muchísimo.

¿Cómo hago renderizado condicional en React? Usas una condición antes de mostrar un componente, por ejemplo !isLoading && !error && <PropertyList />. Solo renderiza si no está cargando y no hay error.

¿Cómo pruebo el estado de error si no tengo una API real?

Como no hay forma de simular un error todavía, existe un truco temporal: cambiar el estado error a true solo para verlo [07:30]. Pero eso no basta, porque el error necesita un mensaje.

Para probarlo de verdad, comentamos el seteo de propiedades en el try y pegamos una línea que dispare un error simulado con throw. El try detecta el error, el catch lo atrapa y muestra "No pudimos cargar las propiedades" [08:40].

Al refrescar verás la secuencia completa: primero "cargando", luego el mensaje de error. Como hubo error y la carga terminó, el PropertyList nunca se renderiza, pero el usuario siempre está informado de lo que sucede.

Después de probar, borra el error simulado, descomenta el seteo de propiedades y elimina el código viejo. Mantener los archivos limpios importa tanto como que funcionen.

¿Qué pasa cuando el listado de propiedades viene vacío?

Un caso más cercano a la realidad es que el listado llegue vacío. En el archivo properties, puedes comprimir el bloque de código (una ventaja de los editores modernos que facilita la lectura) y comentar los objetos para dejar el array sin datos [10:05].

Esto no genera un error. Es una carga de elementos vacíos con el mismo formato, pero sin datos. El resultado es el mensaje "No encontramos alojamientos con esos criterios", exactamente lo que verías tras una búsqueda que no arroja resultados.

Con estados de carga, éxito y error bien manejados, tu app se comporta de forma mucho más parecida a una aplicación real. En la documentación oficial de JavaScript encontrarás recursos útiles para aplicar validaciones y condicionales de datos como los que usamos aquí.

¿Te animas a organizar mejor tus componentes y carpetas en el siguiente paso? Cuéntame en los comentarios cómo estás manejando tus estados de error.