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.
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ística | Server Components | Client Components |
|---|---|---|
| Renderizado | Se ejecutan una sola vez en el servidor, antes de enviar HTML al cliente. | Se renderizan en el cliente (navegador). |
| Interactividad | No tienen Hooks de estado (useState, useEffect). Son ideales para UI estática. | Tienen acceso a todos los Hooks y son interactivos. |
| Acceso a Datos | Acceso directo a bases de datos, sistemas de archivos, etc. | Requieren fetching de datos a través de una API. |
| Uso de Promesas | Usan async/await directamente en el componente. | Aquí es donde brilla el Hook use(). |
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.
use() pausa temporalmente el renderizado hasta que la promesa se resuelva (o se rechace), extrayendo el valor final.use() espera una promesa, React automáticamente encuentra el Suspense Boundary más cercano y muestra el fallback (loading state).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).use()?| Contexto | ¿Se usa use()? | Alternativa / Recomendación |
|---|---|---|
| Client Components | SÍ. Este es el escenario principal donde use() simplifica el Data Fetching. | N/A |
| Server Components | NO. | Usa async/await directamente en la función del componente. |
| Server Actions | NO. | Usa async/await directamente en la función de la acción. |
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.
use() y Server Components// 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; use() lee el valor de una promesa directamente.
Si aún no se resuelve, React “suspende” el render y muestra el fallback del Suspense.useState ni useEffect.Si quieres agregar el loading, sería así:
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.
use()) ¡Este es el enfoque preferido cuando es posible! Aquí se usa async/await directamente.
// ✅ 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>
);
} async, React/Next sabe que debe renderizarlo en el servidor.await fetch(...) se ejecuta directamente (sin hooks).Si lo usas en Next.js, puedes envolverlo con <Suspense fallback={<div>Cargando...</div>}> en el componente padre.
Por ejemplo:
// 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).
import { Suspense } from "react";
import UsersList from "./UsersList";
export default function Page() {
return (
<Suspense fallback={<div>Cargando usuarios...</div>}>
<UsersList />
</Suspense>
);
} 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.
// 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>
);
} useEffect + useState que solo se usa para manejar la promesa de fetching.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.