Contenido del curso

Características Adicionales y Herramientas

Manejo de errores con useActionState en Next.js

Resumen

El manejo de errores en Next.js cambia cuando trabajas con React Server Components y Server Actions. Aquí descubrirás cómo integrar errores con Server Actions, gestionarlos dentro de páginas y configurar un manejador global, todo con las herramientas que el framework recomienda.

Si vienes de manejar errores con React Query y su variable de estado, este enfoque te resultará familiar pero con matices propios del server side. Y aquí viene lo interesante: Next.js propone evitar el try/catch tradicional en favor de patrones más declarativos.

¿Cómo manejar errores con useActionState en Server Actions?

Cuando usas un formulario con una Server Action, lo natural es darle feedback al usuario sobre lo que está pasando. Para eso existe el hook useActionState de React, pensado precisamente para acciones del servidor [3:00].

El hook recibe dos argumentos: la server action y un estado inicial. A cambio te devuelve un array con tres elementos:

  • El state actual, donde puedes guardar el error o cualquier dato que retorne la acción.
  • La action que pasarás al atributo action del <form>.
  • El valor pending, un booleano que indica si la transacción está en curso.

¿Qué es useActionState? Es un hook de React que conecta una Server Action con el estado del formulario, devolviendo el estado, la acción y un booleano pending para mostrar feedback en la UI.

Para que el hook funcione, tu acción debe cambiar de firma. Ya no recibe solo el payload: ahora recibe primero el prevState y después los datos del formulario. Aunque no uses el estado previo, debes declararlo en la firma de la función.

¿Por qué usar if/else en lugar de try/catch?

Next.js recomienda evitar try/catch dentro de Server Actions por cómo funciona internamente el framework. En su lugar, valida el resultado con condicionales.

Por ejemplo, si tu inserción en base de datos retorna un array, puedes verificar si insertó más de cero elementos. Si todo salió bien, retornas un objeto sin error. Si falló, lanzas un throw new Error('Failed to add the event to the database') [6:30].

Ese mensaje quedará disponible en el state del hook, y desde el componente puedes mostrarlo así:

tsx {state?.error && <p className="error">{state.error}</p>}

Un detalle importante: useActionState solo funciona en componentes de cliente. Si lo intentas en un componente asíncrono del servidor, TypeScript te lo advertirá. Debes agregar 'use client' al inicio del archivo y eliminar el async del componente.

¿Cómo deshabilitar el botón mientras se procesa la acción?

Darle feedback visual al usuario mientras la acción está en curso es una de las prácticas más valiosas para mejorar la experiencia. Tienes dos caminos.

El primero es el hook useFormStatus, que expone información del formulario activo en la página. El segundo, más reciente y directo, es aprovechar el booleano pending que ya devuelve useActionState [9:15].

tsx const [state, action, pending] = useActionState(addBookmark, { error: '' });

<button disabled={pending}>Agregar</button>

Con esto evitas envíos duplicados y comunicas al usuario que algo está sucediendo, sin necesidad de hooks adicionales.

¿Cuándo uso useFormStatus y cuándo pending de useActionState? Usa pending cuando ya tienes useActionState configurado. Usa useFormStatus cuando necesitas el estado del formulario desde un componente hijo sin acceso directo al hook.

¿Cómo funciona el archivo error.tsx en páginas de Next.js?

Los errores controlados son una parte. La otra son los errores que no puedes anticipar: una caída de base de datos, un servicio externo que no responde, una excepción inesperada. Para esos casos, Next.js reserva el archivo especial error.tsx [11:20].

Funciona igual que loading.tsx: lo colocas dentro de la carpeta de la ruta que quieres proteger, por ejemplo app/bookmarks/add/error.tsx. Cuando algo lance una excepción no manejada en esa página, Next.js renderizará automáticamente el componente de error en lugar de la pantalla genérica.

El componente recibe dos props clave:

  • error: el objeto del error capturado.
  • reset: una función obligatoria que reinicia el error boundary y permite reintentar.

Usar reset es indispensable para que tu aplicación siga funcionando después del fallo. Lo conectas a un botón de "Intentar de nuevo" para que el usuario pueda recuperarse sin recargar.

La recomendación es personalizar este archivo para que se parezca al resto de tu UI. Mientras más coherente sea la pantalla de error con el diseño general, mejor será la experiencia.

¿Qué es el global-error.tsx y cuándo se ejecuta?

Además del error.tsx por ruta, puedes crear un global-error.tsx en la raíz de app/. Este archivo captura cualquier error que no haya sido manejado por un error.tsx específico [14:40].

Es decir, si olvidas configurar un error boundary en una página concreta, la excepción burbujea hasta el manejador global. Funciona como una red de seguridad final.

Hay un detalle crítico: el global error no se ejecuta en modo desarrollo. Si quieres verlo en acción, tienes que hacer un deploy a producción o correr el servidor en modo production localmente.

¿Por qué global-error.tsx no aparece en desarrollo? Next.js muestra su overlay de errores en dev para facilitar el debugging. El componente global solo se activa en builds de producción.

Como buena práctica, siempre conviene manejar los errores dentro de las páginas individuales antes de depender del global. Cuanto más personalizado y contextual sea el mensaje, más confianza transmite a tus usuarios. Estas páginas también te servirán como punto de entrada para observabilidad, un tema que conecta directo con la siguiente clase.

¿Ya estás manejando errores en tus Server Actions con este patrón? Cuéntame en los comentarios cómo lo estás aplicando en tus proyectos.