use es una API de React 19 que lee un valor de una promesa o de un contexto mientras un componente renderiza. use(promise) pausa el componente hasta que la promesa se resuelve, mostrando mientras tanto el fallback del <Suspense> más cercano; use(context) funciona como useContext pero puede ir dentro de un if o un bucle.
La función fetchUser de abajo sustituye a una petición real.
El primer renderizado muestra "Loading..." durante un segundo y luego el perfil. Haz clic en User 2: el fallback vuelve mientras la nueva promesa está pendiente. Profile no tiene un estado de carga propio; está escrito como si los datos ya estuvieran ahí.
Cómo funciona use(promise)
Cuando Profile llama a use(userPromise):
- Si la promesa ya se resolvió,
usedevuelve su valor y el renderizado continúa. - Si todavía está pendiente, React deja de renderizar
Profiley muestra el fallback del<Suspense>más cercano por encima. Cuando la promesa se resuelve, React vuelve a renderizarProfile, y esta vezusedevuelve el valor. - Si se rechazó, React muestra en su lugar el error boundary más cercano.
React recuerda el resultado en el propio objeto de la promesa. Por eso la promesa tiene que ser el mismo objeto en el siguiente renderizado.
Para mantener el perfil viejo en pantalla mientras carga el siguiente, define la promesa dentro de una transición. React entonces espera en lugar de volver a mostrar el fallback:
<button onClick={() => startTransition(() => setUserPromise(fetchUser(2)))}>User 2</button>
Dónde crear la promesa
Esta es la parte que confunde. Escribir la llamada de fetch dentro del componente que la lee parece natural y no funciona:
// Do not do this
function Profile({ id }) {
const user = use(fetchUser(id)); // a new promise on every render
return <p>{user.name}</p>;
}
Cada renderizado llama a fetchUser y recibe una promesa nueva y pendiente. Profile se suspende. Cuando esa promesa se resuelve, React vuelve a renderizar Profile, lo que crea otra promesa pendiente, que vuelve a suspender. El componente nunca muestra los datos, y la pestaña de red se llena de peticiones.
Crea la promesa en algún lugar que no se vuelva a ejecutar en cada renderizado del lector:
- En un padre, guardada en el estado (como en el primer ejemplo) o creada en un manejador de eventos.
- A nivel de módulo, cuando los datos no dependen de las props:
const configPromise = fetchConfig();encima del componente. - En una caché con clave por los argumentos, para que el mismo id devuelva la misma promesa.
- En un framework: un Server Component puede pasar una promesa a un componente de cliente como prop, y los loaders de rutas hacen lo mismo. Este es el caso para el que se diseñó
use.
Aquí está la versión con caché, para que un componente pueda pedir datos por id y aun así recibir una promesa estable:
Recorre las tres ciudades y vuelve a una que ya abriste. La consola registra una petición por ciudad, y una ciudad que ya viste aparece sin el fallback, porque su promesa ya se resolvió. Borra la comprobación if (!cache.has(city)) y el componente vuelve a suspenderse para siempre.
Una caché real también necesita una forma de expirar entradas. Las librerías de datos y los frameworks se encargan de eso, y por eso la mayoría de las apps obtienen sus promesas de uno de ellos.
use(context), incluso dentro de un if
use(SomeContext) devuelve el mismo valor que useContext(SomeContext). La diferencia es dónde puedes llamarlo. Todos los demás hooks deben ejecutarse en el nivel superior, en el mismo orden en cada renderizado (las reglas de los hooks). use se puede llamar después de un return temprano, dentro de una condición o en un bucle.
Haz clic en el botón para alternar entre las dos ramas. Cambia use(UserContext) por useContext(UserContext) y el código rompe las reglas de los hooks, porque el hook se ejecutaría en algunos renderizados y en otros no.
use igual tiene límites: llámalo solo mientras renderizas un componente o dentro de un hook personalizado. En un manejador de eventos o un efecto, usa un valor del contexto que ya obtuviste durante el renderizado.
Errores: error boundaries, no try/catch
Cuando la promesa se rechaza, el error va al error boundary más cercano, igual que un error de renderizado.
Abre Post 2 y el boundary muestra el mensaje de error. Vuelve a abrir Post 1 y funciona: key={id} le da al boundary un estado nuevo para cada publicación, así que no se queda mostrando el error viejo.
No puedes capturar un use pendiente o rechazado con try/catch. Mientras la promesa está pendiente, use interrumpe el renderizado lanzando un valor especial, y un catch alrededor se lo tragaría. El valor capturado es un error cuyo mensaje empieza con "Suspense Exception: This is not a real error!", y en desarrollo React también registra "use was called from inside a try/catch block". Para mostrar un valor de respaldo en lugar de una pantalla de error, maneja el rechazo en la promesa antes de pasarla hacia abajo:
const postPromise = fetchPost(id).catch(() => 'This post could not be loaded.');
use comparado con obtener datos en useEffect
El patrón clásico de cliente obtiene los datos en un efecto y guarda tres piezas de estado:
function Profile({ id }) {
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
let ignore = false;
fetchUser(id).then(
(u) => !ignore && setUser(u),
(e) => !ignore && setError(e),
);
return () => {
ignore = true;
};
}, [id]);
if (error) return <p>Error</p>;
if (!user) return <p>Loading...</p>;
return <p>{user.name}</p>;
}
useEffect | use | |
|---|---|---|
| Cuándo empieza la petición | después de que el primer renderizado está en pantalla | cuando se crea la promesa, posiblemente antes de que el componente renderice |
| Estado de carga | tu propio if (!user) | el <Suspense> más cercano |
| Errores | tu propio estado error | el error boundary más cercano |
| Condiciones de carrera | las proteges tú (ignore) | el componente siempre lee la promesa que recibió |
| Quién crea la promesa | el componente | un padre, una caché o un framework |
La versión con efecto es autónoma, y por eso sigue siendo el enfoque más común en apps sin framework; la página de obtener datos lo cubre por completo. use brilla cuando algo por encima del componente inicia la petición pronto y le pasa la promesa hacia abajo.
Preguntas frecuentes
¿Qué hace el hook use en React?
use(resource) devuelve el valor de una promesa o de un contexto. Con una promesa, el componente se suspende hasta que se resuelve y el <Suspense> más cercano muestra su fallback; si se rechaza, se muestra en su lugar el error boundary más cercano.
¿Se puede llamar a use de forma condicional?
Sí. use es el único hook que puedes llamar dentro de sentencias if, bucles y después de un return temprano. Igual tiene que llamarse desde un componente o un hook, nunca desde un manejador de eventos o un efecto.
¿Por qué use(fetch()) dentro de mi componente se repite para siempre?
Cada renderizado crea una promesa nueva. El componente se suspende con ella, React vuelve a renderizar cuando se resuelve, y ese renderizado crea otra promesa pendiente. Crea la promesa fuera del renderizado: en el estado de un padre, a nivel de módulo, en una caché o en un loader del framework.
¿Puedo envolver use en try/catch?
No. Cuando una promesa está pendiente, use interrumpe el renderizado lanzando algo, y capturarlo lo rompe. Maneja una promesa rechazada con un error boundary, o agrega .catch() a la promesa para que se resuelva con un valor de respaldo.
¿Debo reemplazar la obtención de datos con useEffect por use?
use necesita una promesa que se crea una vez y se reutiliza, que es lo que te dan los frameworks y las librerías de datos. En una app de cliente normal, obtener datos en un efecto (o con una librería como TanStack Query) sigue siendo habitual y está bien.