Hook use
Lee el valor de una promesa o contexto durante el renderizado — la nueva primitiva de React 19 para datos asíncronos y contexto condicional.
Receta
Tarjeta de referencia rápida — lista para copiar y pegar.
// Lee una promesa (se suspende hasta que se resuelva)
const data = use(dataPromise);
// Lee contexto (funciona en condiciones y bucles — a diferencia de useContext)
if (showTheme) {
const theme = use(ThemeContext);
}Cuándo usarlo: Tienes una promesa creada fuera del componente (pasada como prop o desde una caché) y quieres leer su valor con Suspense, o necesitas leer contexto condicionalmente.
Ejemplo en funcionamiento
"use client";
import { Suspense, use, useState } from "react";
interface User {
id: number;
name: string;
email: string;
}
function fetchUser(id: number): Promise<User> {
return fetch(`https://jsonplaceholder.typicode.com/users/${id}`).then((res) =>
res.json()
);
}
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise);
return (
<div className="border rounded p-4">
<h3 className="font-semibold">{user.name}</h3>
<p className="text-sm text-gray-600">{user.email}</p>
</div>
);
}
export function UserLoader() {
const [userId, setUserId] = useState(1);
const [userPromise, setUserPromise] = useState(() => fetchUser(1));
function handleLoadUser(id: number) {
setUserId(id);
setUserPromise(fetchUser(id));
}
return (
<div className="space-y-3">
<div className="flex gap-2">
{[1, 2, 3].map((id) => (
<button
key={id}
onClick={() => handleLoadUser(id)}
className={`px-3 py-1 border rounded ${
userId === id ? "bg-blue-600 text-white" : ""
}`}
>
User {id}
</button>
))}
</div>
<Suspense fallback={<p className="text-sm text-gray-500">Cargando usuario...</p>}>
<UserProfile userPromise={userPromise} />
</Suspense>
</div>
);
}Lo que esto demuestra:
use(userPromise)suspendeUserProfilehasta que la promesa se resuelva- El límite de
Suspensemuestra un fallback mientras la promesa está pendiente - Crear una nueva promesa (a través de
setUserPromise) activa una nueva suspensión - La promesa se crea en el padre y se pasa como prop — no se crea durante el renderizado
Análisis profundo
Cómo funciona
usepuede leer dos tipos de valores: Promesas y Contextos de React- Para promesas:
usesuspende el componente hasta que la promesa se resuelva, luego devuelve el valor resuelto. Si la promesa se rechaza, lanza hacia el límite de error más cercano - Para contexto:
uselee el valor del proveedor más cercano, al igual queuseContext, pero a diferencia deuseContext, puede llamarse dentro de condiciones, bucles y retornos tempranos useno es técnicamente un hook — no sigue las "reglas de hooks" respecto a llamadas condicionales. Sin embargo, solo puede llamarse durante el renderizado (no en manejadores de eventos o efectos)- La promesa debe crearse fuera del componente de renderizado o estar en caché — crear una nueva promesa en cada renderizado causa suspensión infinita
Parámetros y valores de retorno
| Parámetro | Tipo | Descripción |
|---|---|---|
resource | Promise<T> o Context<T> | Una promesa para leer, o un contexto de React para consumir |
| Retorno | Tipo | Descripción |
|---|---|---|
value | T | El valor resuelto de la promesa, o el valor de contexto actual |
Variaciones
Lectura de contexto condicional:
function Toolbar({ isLoggedIn }: { isLoggedIn: boolean }) {
if (isLoggedIn) {
const user = use(UserContext); // Esto está permitido — a diferencia de useContext
return <p>Bienvenida, {user.name}</p>;
}
return <p>Por favor inicia sesión</p>;
}Leyendo una promesa en caché (patrón común):
// Guarda la promesa en caché para que no se recree en cada renderizado
const cache = new Map<string, Promise<Data>>();
function getData(key: string): Promise<Data> {
if (!cache.has(key)) {
cache.set(key, fetch(`/api/${key}`).then((r) => r.json()));
}
return cache.get(key)!;
}
function DataDisplay({ dataKey }: { dataKey: string }) {
const data = use(getData(dataKey));
return <div>{data.title}</div>;
}Con límite de error:
<ErrorBoundary fallback={<p>Algo salió mal</p>}>
<Suspense fallback={<Spinner />}>
<AsyncComponent dataPromise={promise} />
</Suspense>
</ErrorBoundary>Componente de servidor pasando promesa a componente de cliente:
// Componente de servidor
async function Page() {
const dataPromise = fetchData(); // No esperes — pasa la promesa
return (
<Suspense fallback={<Loading />}>
<ClientComponent dataPromise={dataPromise} />
</Suspense>
);
}
// Componente de cliente
"use client";
function ClientComponent({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise);
return <div>{data.title}</div>;
}Notas de TypeScript
// El tipo se infiere de la promesa o contexto
const user = use(userPromise); // User (inferida de Promise<User>)
const theme = use(ThemeContext); // Theme (inferida de Context<Theme>)
// Tipado explícito cuando sea necesario
const data = use<ApiResponse>(dataPromise);
// La reducción de tipo de contexto funciona igual que useContext
const ctx = use(MyContext);
if (!ctx) throw new Error("Missing provider");Trampas
-
Crear promesas durante el renderizado — Escribir
use(fetch("/api/data"))dentro de un componente crea una nueva promesa en cada renderizado, causando suspensión infinita. Solución: Crea la promesa fuera del componente, en un padre, o en una caché. -
Sin manejo de rechazo en el componente — Si la promesa se rechaza,
uselanza el error. Sin un límite de error, esto bloquea la aplicación. Solución: Siempre envuelve los componentes que consumenuseen un límite de error. -
No es un hook completo —
usepuede llamarse condicionalmente, pero aún solo puede llamarse durante el renderizado. Llamarlo en un manejador de eventos ouseEffectno funciona. Solución: Llama ausesolo en el cuerpo del componente durante el renderizado. -
La identidad de la promesa importa — Si pasas un nuevo objeto de promesa (misma URL pero nueva llamada
fetch), React lo trata como un nuevo recurso y re-suspende. Solución: Guarda en caché o memoriza tus promesas para que la misma solicitud lógica devuelva el mismo objeto de promesa. -
No es un reemplazo para bibliotecas de obtención de datos —
usemaneja la lectura de una promesa con Suspense, pero no proporciona almacenamiento en caché, deduplicación o revalidación. Solución: Usausecon una capa de almacenamiento en caché, o usa una biblioteca de obtención de datos como TanStack Query.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
useEffect + useState | Necesitas obtener datos y gestionar manualmente el estado de carga/error | Quieres estados de carga basados en Suspense |
useContext | Necesitas contexto pero no necesitas lecturas condicionales | Necesitas leer contexto dentro de condiciones o bucles |
| TanStack Query | Necesitas almacenamiento en caché, deduplicación, revalidación y paginación | Lecturas de datos simples y únicas con Suspense |
| Componentes de servidor | Los datos se pueden obtener completamente en el servidor | Los datos dependen del estado del lado del cliente |
await en Componentes de servidor | Estás en un componente de servidor y puedes esperar directamente | Estás en un componente de cliente |
¿Cuándo usar use vs useEffect para obtener datos? Prefiere use cuando quieras transmisión basada en Suspense y la promesa se cree fuera del componente de renderizado. Usa useEffect cuando necesites control detallado sobre estados de carga/error o necesites obtener datos en función de interacciones del lado del cliente.
Preguntas frecuentes
¿Qué tipos de valores puede leer el hook use?
usepuede leer dos tipos: Promesas y Contextos de React.- Para promesas, suspende el componente hasta que la promesa se resuelva.
- Para contexto, funciona como
useContextpero puede llamarse condicionalmente.
¿Por qué use no es técnicamente un hook aunque comience con "use"?
- A diferencia de los hooks,
useno sigue las "reglas de hooks" para llamadas condicionales. - Puedes llamar a
usedentro de sentenciasif, bucles y después de retornos tempranos. - Sin embargo, solo puede llamarse durante el renderizado -- no en manejadores de eventos o efectos.
Trampa: ¿Por qué use(fetch("/api/data")) causa suspensión infinita?
- Llamar a
fetch()dentro del componente crea una nueva promesa en cada renderizado. - React ve una nueva promesa cada vez y re-suspende, creando un bucle infinito.
- Crea la promesa fuera del componente, en un padre, o en una caché.
¿Qué sucede si la promesa pasada a use se rechaza?
uselanza el error, que se propaga al límite de error más cercano.- Sin un límite de error, el rechazo bloquea la aplicación.
- Siempre envuelve los componentes que consumen
useen unErrorBoundary.
¿Cómo guardo una promesa en caché para que no se recree en cada renderizado?
const cache = new Map<string, Promise<Data>>();
function getData(key: string): Promise<Data> {
if (!cache.has(key)) {
cache.set(key, fetch(`/api/${key}`).then(r => r.json()));
}
return cache.get(key)!;
}
function DataDisplay({ dataKey }: { dataKey: string }) {
const data = use(getData(dataKey)); // mismo objeto de promesa
return <div>{data.title}</div>;
}¿Cómo difiere use(Context) de useContext(Context)?
use(Context)puede llamarse dentro de condiciones, bucles y después de retornos tempranos.useContext(Context)debe seguir las reglas de hooks -- solo en el nivel superior.- Ambos leen el valor del Proveedor más cercano. Elige
usecuando necesites lecturas condicionales.
¿Puedo usar el hook use en manejadores de eventos o useEffect?
- No.
usesolo puede llamarse durante el renderizado (el cuerpo del componente). - En manejadores de eventos, usa
awaitdirectamente o gestiona el estado conuseState. - En efectos, usa
async/awaitconuseEffect.
¿Cómo escribo el hook use con tipos en TypeScript?
// El tipo se infiere de la promesa o contexto
const user = use(userPromise); // User (de Promise<User>)
const theme = use(ThemeContext); // Theme (de Context<Theme>)
// Generic explícito cuando sea necesario
const data = use<ApiResponse>(dataPromise);Trampa: ¿Por qué la identidad de la promesa importa al usar use?
- Si pasas un nuevo objeto de promesa (misma URL pero nueva llamada
fetch()), React lo trata como un nuevo recurso. - Esto causa re-suspensión incluso si los datos no han cambiado.
- Guarda en caché o memoriza promesas para que la misma solicitud lógica devuelva el mismo objeto de promesa.
¿Cuándo debo usar use vs useEffect + useState para obtener datos?
- Prefiere
usecuando quieras transmisión basada en Suspense y la promesa se cree fuera del componente. - Usa
useEffect+useStatecuando necesites control detallado de carga/error o obtener datos en función de interacciones del cliente. useno proporciona almacenamiento en caché, deduplicación o revalidación -- emparéjalo con una capa de almacenamiento en caché para uso en producción.
¿Cómo paso una promesa de un componente de servidor a un componente de cliente?
// Componente de servidor
async function Page() {
const dataPromise = fetchData(); // No esperes
return (
<Suspense fallback={<Loading />}>
<ClientComponent dataPromise={dataPromise} />
</Suspense>
);
}
// Componente de cliente
"use client";
function ClientComponent({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise);
return <div>{data.title}</div>;
}Relacionado
- useContext — lectura de contexto tradicional (no puede ser condicional)
- useActionState — acciones de formulario que producen promesas
- useTransition — envuelve actualizaciones de estado que crean nuevas promesas
- useOptimistic — muestra el estado predicho mientras las promesas se resuelven