What's new about the use API (reading resources, Promise, etc.)?
What use() is
use()is a new React API that lets you directly read asynchronous resources (Promise) or contexts (Context) during rendering, without hooks, without useEffect, and without local state.
Previously, React did not let you "wait" for promises inside a component -
you had to use useEffect(), useState(), data loaders, Suspense wrappers, and so on.
Now React can "understand" promises on its own.
Syntax
const data = use(resource);- if
resourceis a Promise, React suspends the render until the promise resolves, and then continues rendering with the result; - if
resourceis a context,use()simply returns the current value (the equivalent ofuseContext()).
How it works
React 19 added support for asynchronous rendering at the core level.
Now, if a component calls use(promise):
- React "sees" that it's a Promise;
- It "suspends" the component's render;
- It shows the nearest
<Suspense fallback={...}>; - When the promise resolves, React resumes rendering with the received data.
This turns asynchronous code into a pure declaration of data.
Example 1. Reading data directly from a Promise
Before React 19:
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user').then(r => r.json()).then(setUser);
}, []);
if (!user) return <Spinner />;
return <h1>{user.name}</h1>;
}Downsides: state, effects, extra renders, "flicker" on the first load.
Now with React 19 + use():
function fetchUser() {
return fetch('/api/user').then(r => r.json());
}
function UserProfile() {
const user = use(fetchUser()); // React itself will wait for the response
return <h1>{user.name}</h1>;
}All the asynchronous behavior is handled inside React -
no useEffect and no useState, everything is synchronous and declarative.
If the data is not ready yet, React shows the Suspense fallback.
Example 2. Working together with <Suspense>
function App() {
return (
<Suspense fallback={<Spinner />}>
<UserProfile />
</Suspense>
);
}React "freezes" the tree until use(fetchUser()) returns a result,
and shows <Spinner /> while waiting.
Example 3. Using use() with context
const ThemeContext = createContext('light');
function Toolbar() {
const theme = use(ThemeContext); // instead of useContext(ThemeContext)
return <div className={theme}>Toolbar</div>;
}use(context) is the modern, shorter form of useContext(context)
(works for both Server Components and Client Components).
Example 4. Working with async functions and Suspense
async function getPost(id) {
const res = await fetch(`/api/posts/${id}`);
return res.json();
}
function Post({ id }) {
const post = use(getPost(id)); // React itself will suspend the render
return <article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>;
}If getPost() returns a Promise, React itself:
- suspends the component;
- shows the
fallback; - continues once
postis ready.
Example 5. Combining with server Actions (React Server Components)
In React 19, server components can now also use use() to wait for data:
// Server Component
import { getUserData } from '@/lib/data';
export default function Page() {
const user = use(getUserData());
return <Profile user={user} />;
}On the server, React waits for getUserData(),
generates the HTML, and sends the client the already-ready markup without "flicker".
How use() relates to Suspense and Concurrent Rendering
| Mechanism | Role |
|---|---|
Suspense | Shows a "fallback" while the data is not ready |
Concurrent Rendering | Lets React suspend and resume rendering |
use() | Triggers waiting for data during render |
Together, these three technologies give "asynchronous React": data, components, and transitions can now be awaited right inside JSX, without imperative code.
Example 6. Combining with Actions
async function createPostAction(formData) {
await api.createPost(formData);
return getAllPosts(); // returns a Promise
}
function Posts() {
const posts = use(getAllPosts());
return (
<form action={createPostAction}>
<ul>
{posts.map(p => <li key={p.id}>{p.title}</li>)}
</ul>
<input name="title" />
<button>Add</button>
</form>
);
}After the Action runs, React automatically calls use() again
to re-read the data (the equivalent of a "refetch").
When use() is useful
Ideal scenarios:
- Asynchronous data loading in Server Components;
- SSR + Streaming Suspense - reading an API without
useEffect; - Forms and Actions, where the result is used in the UI right away;
- Integration with Suspense and React Cache (for example, the
cache(fetch)pattern).
When you should NOT use it
- In older projects without Concurrent Rendering (
React <18); - In components where you need to manually control loading (for example, polling, websockets);
- In "purely client-side" parts of the UI where Suspense is not used.
Important to remember
use()can only be called during render, like an ordinary hook;- React itself detects that it's a Promise and does the "suspend";
- Works only with Concurrent Rendering enabled (React 18+);
- Does not replace
useStateoruseEffect- it is a different paradigm: declarative waiting for data; - In React 19
use()is stable, but in React 18 it was experimental.
Summary
use()is a new React 19 API for reading promises, resources, and contexts right during render. It makes working with asynchronous data clean, synchronous-looking, and fully integrated withSuspense. It is the foundation of the new asynchronous React model - together withSuspense,Actions,Server Components, anduseOptimistic().
In short:
| Capability | Description |
|---|---|
use(promise) | React "waits" for the Promise's result, suspends the render |
use(context) | The equivalent of useContext(context) |
| Suspense integration | React shows the fallback while the data is not ready |
| Works with Server Components | Yes |
| Works with Actions | Yes |
Imperative code (useEffect) is not needed | Yes |
| Status in React 19 | Stable |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.