React 19 introduces several exciting new features, and one of the most impactful is the use() API. This new API simplifies how you fetch and consume data inside your React components — making your code cleaner, more declarative, and better integrated with React’s concurrent rendering and Suspense.
In this article, we’ll explore:
- What the use() API is
- How it works under the hood
- How to use it with fetch() for data fetching
- A complete working example using React 19
What is the use() API?
use() is a new React hook-like function that lets you unwrap promises (or contexts) directly inside a component, instead of using useEffect and useState.
Previously, fetching data looked like this:
import { useEffect, useState } from "react";
function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then(setUsers);
}, []);
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}This works, but it’s imperative and has extra state management.
With React 19’s use(), you can do this declaratively:
import { use } from "react";
const usersPromise = fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json());
export function Users() {
const users = use(usersPromise);
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}When use() sees a Promise, it suspends the component until it resolves. This integrates naturally with <Suspense> boundaries.
How use() Works
- use(promise) will throw the promise while it’s pending
- React catches it via Suspense
- React waits, then retries rendering with the resolved value
- If the promise rejects, React shows the nearest error boundary
This makes asynchronous rendering first-class in React.
Building a React 19 App with Vite
Let’s set up a minimal project using Vite and React 19 to demonstrate this.
- Create a new Vite + React project
npm create vite@latest my-app
cd my-app
npm install
Inside src/App.jsx, add this code:
import { Suspense } from "react";
import { use } from "react";
// Fetch data once and reuse the promise
const usersPromise = fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => {
if (!res.ok) throw new Error("Failed to fetch users");
return res.json();
});
function Users() {
// use() unwraps the resolved data from the promise
const users = use(usersPromise);
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
export default function App() {
return (
<Suspense fallback={<p>Loading users...</p>}>
<Users />
</Suspense>
);
}The new use() API in React 19 represents a paradigm shift for how we fetch and consume async data in React. It eliminates boilerplate, improves code clarity, and leverages React’s concurrent features seamlessly.
To read more about What are the Key Features in React 19, refer to our blog What are the Key Features in React 19.