我正在学习 Next.js,并且我正在尝试在客户端组件内渲染服务器异步组件:
画廊.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>
);
}
页面.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>
);
}
我正在重构过程中,我想用useRef向表单添加重置,所以我添加了
use client
。当我将 Gallery 提取到另一个组件中后,开始出现错误:
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)
如果我将``use server'`添加到图库,我收到此错误:
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)
添加React.Suspense就解决了所有问题:
<Suspense fallback={<p>loading...</p>}>
<Gallery />
</Suspense>
那么问题来了,使用异步服务器组件时Suspense是必须的吗?我只知道什么是允许的,通过询问这个我不在乎它是否会冻结直到异步操作完成。
我问ChatGPT,它首先给出的答案是您可以将服务器组件包含在客户端组件中。当我问及悬念时,他只提到了延迟。我问的是不使用 Suspense 时出现的神秘错误。
这看起来很常见,但我找不到任何它是如何工作的。
在客户端组件中导入服务器组件在 Next.js 中不是有效模式。
正确的方法是 将服务器组件作为 prop 传递给客户端组件,并且一般来说,将客户端组件沿着你的 组件树移动。
所以你不需要使用Suspense(因为你将完全避免将服务器组件导入到客户端组件)。 在某种程度上,通过使用 Suspense,您正在“欺骗”Next.js,使其不返回实际上应该返回的错误。
针对这个特定场景,您可以采取多种方法。在您的情况下,最简单的方法可能是将您的主页和图库保留为常规服务器组件,并使您的表单成为客户端组件:然后您可以在其中使用 useRef ,然后将其导入到您的主页中。