jcubic
jcubic

Reputation: 66590

Do you need to use Suspense when using async React Server Component inside client component in Next.js?

I'm learning Next.js, and I'm trying to render Server async Component inside client Component:

Gallery.tsx

import { get_images } from '@/utils';
import styles from './Gallery.module.css';

export default async function Gallery() {
  const images = await get_images();
  return (
    <ul className={styles.gallery}>
      {images.map(file => {
        const url = `https://example.com/images/${file}`;
        return (
          <li key={file}>
            <span>
              {/* when using Image got a double error */}
              <img src={url} alt="image" />
            </span>
          </li>
        );
      })}
    </ul>
  );
}

page.tsx

'use client';
import { useRef } from 'react';
import { revalidatePath } from 'next/cache'

import styles from "./page.module.css";
import { upload } from '@/git';
import Gallery from '@/components/Gallery';

export default function Home() {
  const formRef = useRef();

  async function uploadAction(formData: FormData) {
    await upload(formData);
    revalidatePath('/');
  }
  
  return (
    <main className={styles.main}>
      {/* <Gallery /> */}
      <h2>Upload form</h2>
      <div className={styles.form}>
        <form action={uploadAction}>
        </form>
      </div>
   </main>
  );
}

I'm in a process of refactoring, I wanted to add reset to the form with useRef, so I added use client. After I extracted the Gallery into another component, started to get error:

app-index.js:33 Warning: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding `'use client'` to a module that was originally written for the server.
    at Gallery
    at main
    at Home (webpack-internal:///(app-pages-browser)/./src/app/page.tsx:23:66)

If I add ``use server'` to Gallery, I got this error:

app-index.js:33 Warning: Cannot update a component (`Router`) while rendering a different component (`proxy`). To locate the bad setState() call inside `proxy`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
    at proxy
    at main
    at Home (webpack-internal:///(app-pages-browser)/./src/app/page.tsx:23:66)

All problems are solved when adding React.Suspense:

      <Suspense fallback={<p>loading...</p>}>
        <Gallery />
      </Suspense>

So the question is, is Suspense a must when using async server components? I only what to know what is allowed, by asking this I don't care if it will freeze until async action finish.

I was asking ChatGPT, and it first gives answer that you can just include Server component inside Client component. When I asked about Suspense, he only mentioned a delay. I'm asking about cryptic errors when not using Suspense.

This looks like pretty common, but I'm not able to find anything how this works.

Upvotes: 1

Views: 282

Answers (1)

titon
titon

Reputation: 1

Importing a server component in a client component is not a valid pattern in Next.js.

The correct approach would be to pass server components to client components as props and, generally speaking, moving client components down your component tree.

So you don't need to use Suspense (because you should be avoiding importing server components in client components entirely). In a way, by using Suspense you are "tricking" Next.js into not throwing an error it should actually throw.

There are many approaches you can take for this specific scenario. The easiest in your case would probably be just keeping your homepage and gallery as regular server components, and extracting your form as a client component instead: then you could use useRef in it, and just import the new component in your homepage (which is the "moving the client component down the tree" approach).

Upvotes: 0

Related Questions