Nuevo Hook use() de React 19

El Hook use(), es una de las adiciones más significativas a React 19, diseñado para simplificar el manejo de datos asíncronos y la integración con Suspense en los Client Components.

Server Components vs Client Components

Antes de sumergirnos en use(), es vital entender el contexto de la nueva arquitectura de React (en especial con frameworks como Next.js, Remix, etc.):

CaracterísticaServer ComponentsClient Components
RenderizadoSe ejecutan una sola vez en el servidor, antes de enviar HTML al cliente.Se renderizan en el cliente (navegador).
InteractividadNo tienen Hooks de estado (useState, useEffect). Son ideales para UI estática.Tienen acceso a todos los Hooks y son interactivos.
Acceso a DatosAcceso directo a bases de datos, sistemas de archivos, etc.Requieren fetching de datos a través de una API.
Uso de PromesasUsan async/await directamente en el componente.Aquí es donde brilla el Hook use().

¿Qué es use()?


El Hook use() es una nueva primitiva de React que permite leer el valor de un recurso asíncrono, como una promesa, durante el renderizado de un Client Component.

  Características Clave

  • Espera Promesas o Recursos Asíncronos: use() pausa temporalmente el renderizado hasta que la promesa se resuelva (o se rechace), extrayendo el valor final.
  • Integración NATIVA con Suspense: Cuando use() espera una promesa, React automáticamente encuentra el Suspense Boundary más cercano y muestra el fallback (loading state).
  • Se puede usar en condicionales y loops: A diferencia de otros Hooks de React, use() sigue las reglas de JavaScript más que las de los Hooks. Esto significa que puedes usarlo dentro de condicionales (if, ? :) y loops (for, while).

¿Dónde se usa use()?

Contexto¿Se usa use()?Alternativa / Recomendación
Client ComponentsSÍ. Este es el escenario principal donde use() simplifica el Data Fetching.N/A
Server ComponentsNO.Usa async/await directamente en la función del componente.
Server ActionsNO.Usa async/await directamente en la función de la acción.

Ejemplo Comparativo: Data Fetching

El Hook use() simplifica notablemente el patrón de fetching de datos al eliminar la necesidad de estado local (useState) y efectos secundarios (useEffect) solo para manejar la promesa.

1El Enfoque Tradicional (Antes de use() y Server Components

javascript
// Client Component Tradicional
import { useState, useEffect } from 'react';

function App() {
const [user, setUser] = useState(null); // ⚠️ Estado para guardar el dato
const [loading, setLoading] = useState(true);

  // ⚠️ useEffect para manejar el side-effect (fetching)
  useEffect(() => {

      // ⚠️ Función para hacer la solicitud fetch
      async function fetchUser() {
          setLoading(true);
          const response = await fetch(`https://devsapihub.com/api-users`);
          const data = await response.json();
          setUser(data);
          setLoading(false);
      }

      // ⚠️ Llamada a la función fetchUser
      fetchUser();
  }, []); // Dependencia clave

  if (loading) return <div>Cargando usuarios...</div>;
  if (!user) return <div>Usuarios no encontrados.</div>;

  return (
      <div>
      <h1>Lista de usuarios:</h1>
      <ol>
          {user.map((u) => (
          <li key={u.id}>{u.name}</li>
          ))}
      </ol>
      </div>
  );
}

export default App;
  Explicación rápida

  • use() lee el valor de una promesa directamente. Si aún no se resuelve, React “suspende” el render y muestra el fallback del Suspense.
  • Ya no necesitas los hooks useState ni useEffect.
  • Ideal para usar junto a React Suspense (para mostrar loading).

Si quieres agregar el loading, sería así:

javascript
import { Suspense, use } from "react";

// ⚠️ Función para hacer la solicitud fetch
async function getUsers() {
  const res = await fetch("https://devsapihub.com/api-users");
  return res.json();
}

// ⚠️ Promesa para hacer la solicitud fetch
const usersPromise = getUsers();

// ⚠️ Función para renderizar la lista de usuarios
function UsersList() {
  const users = use(usersPromise);
  return (
      <ol>
      {users.map((u) => (
          <li key={u.id}>{u.name}</li>
      ))}
      </ol>
  );
}

// ⚠️ Función para renderizar la lista de usuarios
export default function App() {
  return (
      <Suspense fallback={<div>Cargando usuarios...</div>}>
      <h1>Lista de usuarios:</h1>
      <UsersList />
      </Suspense>
  );
}

Así de limpio queda con use() — sin useState, sin useEffect y sin drama.

2El Enfoque con Server Component (Preferido, Sin use())

¡Este es el enfoque preferido cuando es posible! Aquí se usa async/await directamente.

jsx
// ✅ Server Component (React 19 / Next.js 15 compatible)
// No usa use(), ni hooks, ni estado.

export default async function UsersList() {
  // Esto se ejecuta en el servidor
  const res = await fetch("https://devsapihub.com/api-users", {
      cache: "no-store", // 🔁 evita usar caché (opcional)
  });

  if (!res.ok) {
      throw new Error("Error al obtener los usuarios");
  }

  const users = await res.json();

  return (
      <div>
      <h1>Lista de usuarios:</h1>
      <ol>
          {users.map((u) => (
          <li key={u.id}>{u.name}</li>
          ))}
      </ol>
      </div>
  );
}
  Qué pasa aquí:

  • Como el componente es async, React/Next sabe que debe renderizarlo en el servidor.
  • await fetch(...) se ejecuta directamente (sin hooks).
  • El HTML resultante se envía al cliente ya con los datos.

Si lo usas en Next.js, puedes envolverlo con <Suspense fallback={<div>Cargando...</div>}> en el componente padre.

Por ejemplo:

jsx
// app/page.jsx
import { Suspense } from "react";
import UsersList from "./UsersList";

export default function Page() {
  return (
      <Suspense fallback={<div>Cargando usuarios...</div>}>
      <UsersList />
      </Suspense>
  );
}

Este enfoque es el preferido en React 19 y Next.js 15 cuando los datos pueden cargarse en el servidor (más rápido y sin hidratar hooks en el cliente).

jsx
import { Suspense } from "react";
import UsersList from "./UsersList";

export default function Page() {
  return (
      <Suspense fallback={<div>Cargando usuarios...</div>}>
      <UsersList />
      </Suspense>
  );
}

3El Enfoque con use() (Donde brilla use())

Este es el enfoque a usar cuando necesitas interactividad (es un Client Component) pero quieres la limpieza de sintaxis de async/await.

javascript
// Client Component (Usa use() y requiere 'use client')
// ⚡ React 19 - usando el hook use() para manejar el estado de carga
import { use } from "react";

async function getUsers() {
  const res = await fetch("https://devsapihub.com/api-users");
  if (!res.ok) throw new Error("Error al obtener usuarios");
  return res.json();
}

// ⚠️ Nota: fetch() se ejecuta una sola vez (mientras el componente viva)
const usersPromise = getUsers();

export default function App() {
  const users = use(usersPromise); // 👈 Aquí se "suspende" hasta que la promesa se resuelva

  return (
      <div>
      <h1>Lista de usuarios:</h1>
      <ol>
          {users.map((u) => (
          <li key={u.id}>{u.name}</li>
          ))}
      </ol>
      </div>
  );
}
  Cuándo usar `use()`

  • Cuando estás en un Client Component (debido a la necesidad de interactividad o Hooks de estado) y necesitas consumir datos del servidor.
  • Cuando quieres implementar una carga condicional de datos (ej. solo fetch si el toggle está activado).
  • Para simplificar el patrón de useEffect + useState que solo se usa para manejar la promesa de fetching.
  • Siempre que busques una mejor Experiencia de Usuario (UX) aprovechando la funcionalidad de Suspense para mostrar estados de carga.

  Resumen

use() hace el código más limpio y directo: elimina useEffect y useState, funciona dentro de condicionales o bucles, se integra automáticamente con Suspense y reduce muchísimo el boilerplate al manejar datos asíncronos.