Next.js Discord

Discord Forum

NextJS 13 app: Fetch API server-side and feed the response to a client-side component as properties

Answered
Haddock posted this in #help-forum
Open in Discord
HaddockOP
Hi everyone, I'm creating a website using NextJS 13 and I do utilize the new App router.
I aim to use server-side processing whenever possible, and even for components that do need to use client (tailwind-elements) I'd like to fetch the data from API on the server-side and then provide the response to my client-side component as properties.
So far I haven't figured out a way to do it with Next13 App router. As I understood in Next 12 and below I could do getServerSideProps or even getStaticProps in some cases however I'm not sure if it's valid with App router or that it even will work with it.

What I've tried so far is having a async function that performs my request:
export const getFeaturedPosts = async function() {
  const res = await fetch('http://localhost:3000/site/api', { next: { tags: ['featured'] } }) // The result is cached
  return res.json()
}

export const featuredPostsData = await getFeaturedPosts();


However trying to resolve this promise serverside from the top level scope will not work unless I enable some kind of a experimental feature:
// Get All of the data on server
import {featuredPostsData} from '~/utils/posts'

export default function Page() {
  return (
    <>
      <PostCarousel />

      {/* @ts-expect-error Server Component */}
      <Content3 {...featuredPostsData} />
      <AI />
    </>
  );
}


This is the error I get:
- error ./src/utils/posts.js
Module parse failed: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)
Error: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)
Import trace for requested module:


Can yo uplease advise id I'm missing some kind of an obvious trick here?
Answered by joulev
then you can do this
import {getFeaturedPosts} from '~/utils/posts'
export default async function Page() {
  const featured = await getFeaturedPosts();
  return <YourClientComponent featured={featured} />;
}

"use client";
export default function YourClientComponent({ featured }) {
  return <pre>{JSON,stringify(featured)}</pre>;
}
View full answer

8 Replies

@Haddock Hi everyone, I'm creating a website using NextJS 13 and I do utilize the new App router. I aim to use server-side processing whenever possible, and even for components that do need to use client (tailwind-elements) I'd like to fetch the data from API on the server-side and then provide the response to my client-side component as properties. So far I haven't figured out a way to do it with Next13 App router. As I understood in Next 12 and below I could do getServerSideProps or even getStaticProps in some cases however I'm not sure if it's valid with App router or that it even will work with it. What I've tried so far is having a async function that performs my request: export const getFeaturedPosts = async function() { const res = await fetch('http://localhost:3000/site/api', { next: { tags: ['featured'] } }) // The result is cached return res.json() } export const featuredPostsData = await getFeaturedPosts(); However trying to resolve this promise serverside from the top level scope will not work unless I enable some kind of a experimental feature: // Get All of the data on server import {featuredPostsData} from '~/utils/posts' export default function Page() { return ( <> <PostCarousel /> {/* @ts-expect-error Server Component */} <Content3 {...featuredPostsData} /> <AI /> </> ); } This is the error I get: - error ./src/utils/posts.js Module parse failed: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it) Error: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it) Import trace for requested module: Can yo uplease advise id I'm missing some kind of an obvious trick here?
you didn't use top-level await in the code you provided though; this error is caused by a different place in the code
HaddockOP
Hi @joulev thanks for your reply,
I actually did do top-level await, here't the full snippet
apologies for incomplete info above:

export const getFeaturedPosts = async function() {
  const res = await fetch('http://localhost:3000/site/api', { next: { tags: ['featured'] } }) // The result is cached
  return res.json()
}
 
export const featuredPostsData = await getFeaturedPosts();
@Haddock Hi <@484037068239142956> thanks for your reply, I actually did do top-level await, here't the full snippet apologies for incomplete info above: export const getFeaturedPosts = async function() { const res = await fetch('http://localhost:3000/site/api', { next: { tags: ['featured'] } }) // The result is cached return res.json() } export const featuredPostsData = await getFeaturedPosts();
you can enable top-level await.

BUT in this case i think you simply need to move the featuredPostsData inside an async function
import {getFeaturedPosts} from '~/utils/posts'

export default function Page() {
  const featuredPostsData = await getFeaturedPosts();
  return (
    <>
      <PostCarousel />

      {/* @ts-expect-error Server Component */}
      <Content3 {...featuredPostsData} />
      <AI />
    </>
  );
}
HaddockOP
I apologize again for my example code - I guess it's really misleading.
Yes for a server-side component that worked great for me and actually in the snippet above what you see is a component explicitly annotated as Server Component.
Now my issue is that I'm now implementing this Carousel component which has to use client
and I do need that data fetched from API however with client side I'll have to useEffect and this is what I'd like to avoid and have my data provided as properties and fetched server side
@Haddock and I do need that data fetched from API however with client side I'll have to useEffect and this is what I'd like to avoid and have my data provided as properties and fetched server side
then you can do this
import {getFeaturedPosts} from '~/utils/posts'
export default async function Page() {
  const featured = await getFeaturedPosts();
  return <YourClientComponent featured={featured} />;
}

"use client";
export default function YourClientComponent({ featured }) {
  return <pre>{JSON,stringify(featured)}</pre>;
}
Answer
HaddockOP
Oh I see, in fact just moving the await part to Page itself solves the problem! Thanks a lot