This content originally appeared on DEV Community and was authored by Nancy Kataria
The use
API significantly reduces the need for useState
and useEffect
in certain scenarios, particularly for handling asynchronous data fetching. Learn more: React v19 documentation.
How it Works:
-
use(promise)
suspends rendering until the promise resolves. - You no longer need to manually handle loading states (
useState
). -
useEffect
is not required to trigger data fetching.
The Problem
While working with React v19 and Next.js for a full-stack application, a critical limitation arises when trying to fetch API data using the new use
API. Let’s analyze an issue with a scenario where the goal is to stream data from the server component to the client component:
Fetching API Data in a Server Component:
- Initially, an API call is made in a server component using:
import { Suspense } from "react";
import Feedbacks from "../../Components/Feedbacks";
import Feedback from "../../Models/Feedback";
const fetchFeedBacks = async (): Promise<FeedbackResponse[]> => {
try {
const res = await fetch(`http://localhost:3000/api/getFeedbacks`);
if (res.ok) {
throw new Error("Failed to fetch data");
}
return res.json();
} catch (error) {
console.log(error);
return []
}
};
export default function Home() {
const feedbackPromise: Promise<FeedbackResponse[]> = fetchFeedBacks();
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Feedbacks feedbackPromise={feedbackPromise} />
</Suspense>
);
}
- Client Component reading the promise values:
"use client";
import React, { use } from "react";
const Feedbacks = ({ feedbackPromise }: { feedbackPromise: Promise<FeedbackResponse[]> }) => {
const feedbackList: FeedbackResponse[] = use(feedbackPromise);
return (
<div>
{feedbackList?.map((record: FeedbackResponse) => (
<div key={record._id}>
<h5>{record.name}</h5>
<p>{record.feedback}</p>
</div>
))}
</div>
);
};
export default Feedbacks;
- This works well in development but fails in production when building the app using
next build && next start
. - The error occurs because the fetch call inside the server component attempts to access the Next.js API route using
http://localhost:3000
, leading to a connection refusal. The server tries to connect to itself while processing a request, which is not feasible in the production execution context.
Attempted Solutions and Their Problems
1. Switching to a Client Component:
"use client";
const fetchFeedBacks = async (): Promise<FeedbackResponse[]> => {
try {
const res = await fetch(`/api/getFeedbacks`);
if (res.ok) {
throw new Error("Failed to fetch data");
}
return res.json();
} catch (error) {
console.log(error);
return []
}
};
- Making the Home component as a client component and using a relative URL (
/api/getFeedbacks
) to call the API results in hydration issues. - The client and server reconciliation process does not align, leading to Next.js throwing hydration errors.
2. Fetching Data Where It's Needed:
- Normally, you might think of moving the fetch logic to the client component where it's actually used.
- However, with the
use
API, a promise must be passed to the component as a prop, making it harder to manage updates dynamically.
3. Fetching data directly in the Server Component
const fetchFeedBacks = async (): Promise<FeedbackResponse[]> => {
try {
await connectDB();
const feedbackList: FeedbackResponse[] = await Feedback.find({});
return feedbackList;
} catch (error) {
console.log(error);
return [];
}
};
export default function Home() {
const feedbackPromise: Promise<FeedbackResponse[]> = fetchFeedBacks();
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Feedbacks feedbackPromise={feedbackPromise} />
</Suspense>
);
}
A potential workaround is to fetch data directly from the database inside the Home
server component instead of calling the API route. While this initially works, it introduces another issue:
- The
fetchFeedbacks
function works correctly inlocalhost
, but the data becomes stale after building and deploying the app. - Even when submitting new responses through the form, the page displays old data, even after refreshing.
The Only Viable Solution
Given these limitations, the only working solution is to decouple the backend from Next.js entirely:
- Keep the backend running on a different URL (e.g., a separate Node.js/Express server).
- Serve the frontend separately using Next.js.
- Ensure API calls are directed to an external backend rather than relying on Next.js API routes.
This separation avoids the self-referential API request issue and ensures fresh data is always fetched from the backend without running into hydration problems or infinite loops.
Conclusion
The use
API in React 19 introduces powerful capabilities but has significant limitations in full-stack frameworks like Next.js. While it simplifies data fetching, it struggles in scenarios where:
- API routes are hosted within Next.js itself.
- Server components try to fetch from local API endpoints.
- Data freshness is a concern in production.
For full-stack applications, separating the backend and frontend into distinct services seems to be the most reliable approach.
Github Repo for the code.
I would like to know about any possible solutions I might not have tried or comments on anything I might be doing wrong until now. If you have encountered similar issues or found alternative approaches, please feel free to share your insights!
Self-Reminder: "You must be imaginative and strong-hearted. You must try things that may not work. Don’t let anyone define your limits because of where you come from. Anyone can code but only the fearless can be great." - Auguste Gusteau, Ratatouille
This content originally appeared on DEV Community and was authored by Nancy Kataria

Nancy Kataria | Sciencx (2025-01-31T04:46:34+00:00) Limitations of React v19 `use` API in Full Stack Frameworks. Retrieved from https://www.scien.cx/2025/01/31/limitations-of-react-v19-use-api-in-full-stack-frameworks/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.