next.js: Not able to fetch data from Client Component (infinite fetch() calls)
Edit by @acdlite: This is mostly a React issue. We’re working to address it: https://github.com/vercel/next.js/issues/42180#issuecomment-1542434389
Verify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 21.6.0: Mon Aug 22 20:19:52 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T6000
Binaries:
Node: 16.14.2
npm: 8.5.0
Yarn: 1.22.18
pnpm: N/A
Relevant packages:
next: 13.0.0
eslint-config-next: 13.0.0
react: 18.2.0
react-dom: 18.2.0
What browser are you using? (if relevant)
Version 106.0.5249.119
How are you deploying your application? (if relevant)
next dev
Describe the Bug
I was just playing around getting to know next 13 when I tried fetching data from a Client component.
I literally just copy pasted the example from the docs: https://beta.nextjs.org/docs/data-fetching/fetching#example-fetch-and-asyncawait-in-server-components
The Client Component is used inside page.tsx
where its wrapped in
<Suspense fallback={<div>Loading...</div>}></Suspense>
When running that I get:
- Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
- TypeError: Cannot read properties of null (reading ‘use’)
Server Component:
import { Suspense } from "react";
import Fact from "./fact";
export default function Home() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<Fact />
</Suspense>
</div>
)
}
Client Component:
"use client";
import { use } from 'react';
async function getData() {
console.log("fetch")
const res = await fetch('https://catfact.ninja/fact');
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
return res.json();
}
export default async function Fact() {
const name = use(getData());
return (
<div>
{name.fact}
</div>
);
}
Expected Behavior
The root server component in page.tsx
should render right away and the client component should render when the data was fetched. Before the data is fetched it should say Loading…
.
Link to reproduction
https://codesandbox.io/s/reverent-danilo-zgle45?file=/app/fact.tsx
To Reproduce
Open the link or copy paste the code inside your app
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 5
- Comments: 40 (19 by maintainers)
👋 Hi friends! Really appreciate all the investigation and discussion here. I spoke with the team about this and it looks like, perhaps as expected, we don’t have this functionality quite finished yet. We tried to clarify in the docs that fetch is not yet supported in client components - the recommendation right now is to fetch data in server components.
This is a feature that will be supported in the future for sure, but this is a beta release and we’re not quite there yet. Thank you so much for testing out the new app directory, and I’ll update you all here once we do support fetching in client components!
The infinite
use()
client error andcache
server error are roadblock to get next 13 to work@balazsorban44 No, I don’t think so. My mistake. There are no
async
client components in docs that I’m aware of. My apologies…Hi @apostolos Why do the docs have an async on the client components? But either way, I first did it the same way you did but would then face the problem of infinite fetch calls.
I would not stop calling the
getData()
function. When you remove thefetch()
andthe fakeDelay()
it is being called 10000 times per second. Might there be something wrong withuse()
.Nextjs 13 is now stable with
INFINITE
LOOP
BUG
@balazsorban44 The async on the client component was already changed. But there really was one.
The problem actually exactly happens when calling the function with the fetch in
use()
@iSuslov Please be nice to the people working on open source project. Our company is using Next.js 13 and it is amazing!
That did it. Thanks @apostolos
@palmer-cl
cache()
takes a function declaration as the only argument. You are not supposed to call it inside render.See the commented code in my example: https://codesandbox.io/s/next-appdir-use-i43p25?file=/app/fact.tsx
Try this:
Then, inside render call the wrapped function:
I cannot see
async
on the exportedPage
component. Am I missing something? 🤔The
cache()
function seems to be already available in react 18.2.0 somehow…Anyways I tried it and it fixed the infinite fetch issue on client side, but it throws a “Not implemented” error on server. (Remember client components are also rendered on server.)
Related issue: #41852
@apostolos Thank you! So for now we would have to use this (nasty) work around with the double render until they solve it?
@AlexLup06 regarding the infinite calling of fetch, based on the RFC again, the promise passed to use() is supposed to be cached (stable identity between renders).
There is a
cache()
function that we can use in the experimental React release but it’s not implemented yet.I’ve updated my example (https://codesandbox.io/s/next-appdir-use-i43p25?file=/app/fact.tsx) with how it is supposed work (commented out) plus a simple workaround to avoid infinite fetches with a simple caching of the fetch Promise. It’s not correct due to the fact that the cache on the server and the cache on the client are not the same, therefore you get different results from the server render and from the client render.
Soon, Next.js will be able to pass the resolved promise from the server to the client somehow. That should avoid double-rendering (the server result will be used). You can read more about this in the RFC: https://github.com/acdlite/rfcs/blob/first-class-promises/text/0000-first-class-support-for-promises.md#passing-a-promise-from-a-server-component-to-a-client-component