“使用客户端”到模块 NEXT.js 15 中出现错误

问题描述 投票:0回答:1

目前,我正在使用 React 19 将我的 next.js 14 项目升级到 next.js 15,我正面临这个问题,如果您能帮助我,我将很高兴。

这是我的应用程序主页这是电子商务网站

export const revalidate = 0;

import Container from "./components/Container";
import HomeBanner from "./components/HomeBanner";
import NullData from "./components/NullData";
import getProducts, { IProductParams } from "@/actions/getProducts";
import ShuffledProducts from "./components/ShuffledProducts"; // Direct import

interface HomeProps {
  searchParams: IProductParams;
}

export default async function Home({ searchParams }: HomeProps) {
  const { category, searchTerm } = searchParams;

  // Fetch products from the server
  const products = await getProducts({ category, searchTerm });

  if (products.length === 0) {
    return <NullData title="OOPS ! No Products Found" />;
  }

  return (
    <div className="p-8">
      <Container>
        <div className="pb-8">
          <HomeBanner />
        </div>
        {/* Directly render the Client Component */}
        <ShuffledProducts products={products} />
      </Container>
    </div>
  );
}

这是我的容器(导入到上面的页面)

interface ContainerProps{
    children: React.ReactNode
}
const Container: React.FC<ContainerProps> = ({ children }) => {
  return (<div className="
  max-w-[1920px] 
  mx-auto 
  xl:px-20 md:px-2 px-4">{children}</div>);
};
 
export default Container;

这是我的 ShuffledProducts

"use client";

import ProductCard from "./products/ProductCard";

interface ShuffledProductsProps {
  products: any[];
}

export default function ShuffledProducts({ products }: ShuffledProductsProps) {
  function shuffleArray(array: any[]) {
    for (let i = array.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  }

  const shuffledProducts = shuffleArray(products);

  return (
    <div
      className="grid 
      grid-cols-2
      sm:grid-cols-3 
      lg:grid-cols-6
      xl:grid-col-5 
      2xl:grid-col-6 
      gap-8"
    >
      {shuffledProducts.map((product: any) => (
        <ProductCard key={product.id} data={product} />
      ))}
    </div>
  );
}

这是我的获取产品

import prisma from "@/libs/prismadb";
export interface IProductParams {
  category?: string | null;
  searchTerm?: string | null;
}

export default async function getproducts(params: IProductParams) {
  try {
    const { category, searchTerm } = params;
    let searchString = searchTerm;

    if (!searchTerm) {
      searchString = "";
    }

    const query: any = {};

    if (category) {
      query.category = category;
    }

    const products = await prisma.product.findMany({
      where: {
        ...query,
        OR: [
          {
            name: {
              contains: searchString,
              mode: "insensitive",
            },
            description: {
              contains: searchString,
              mode: "insensitive",
            },
          },
        ],
      },
      include: {
        reviews: {
          include: {
            user: true,
          },
          orderBy: {
            createdDate: "desc",
          },
        },
      },
    });
    return products;
  } catch (error: any) {
    console.error("Error fetching products:", error);
    throw new Error("Failed to fetch products.");
  }
}

我的问题是我收到吹气控制台错误

Console Error

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.


Console Error

A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework.

而且我在终端中也收到此错误

Error: Route "/" used `searchParams.category`. `searchParams` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
    at category (src\app\page.tsx:14:10)
  12 |
  13 | export default async function Home({ searchParams }: HomeProps) {
> 14 |   const { category, searchTerm } = searchParams;
     |          ^
  15 |
  16 |   // Fetch products from the server
  17 |   const products = await getProducts({ category, searchTerm });

在我的 Next.js 14 版本中,这些错误没有发生,我希望您帮助解决我的 Next.js 15 项目中的这些错误。

reactjs typescript next.js next.js15
1个回答
0
投票

Next.js 15 引入了一些重大更改,包括 异步参数

这是来自 docs 的示例,您的页面参数必须如何与新的 Next.js 版本兼容:

// Before (Next.js 14)
type Params = { slug: string }
 
export default async function Page({params,}: {params: Params}) {
  const { slug } = params
}
 
// After (Next.js 15+)
type Params = Promise<{ slug: string }>
 
export default async function Page(props: {params: Params}) {
  const params = await props.params
  const slug = params.slug
}

因此,您的主页代码应类似于以下内容:

export const revalidate = 0;

import Container from "./components/Container";
import HomeBanner from "./components/HomeBanner";
import NullData from "./components/NullData";
import getProducts, { IProductParams } from "@/actions/getProducts";
import ShuffledProducts from "./components/ShuffledProducts"; // Direct import

interface HomeProps {
  searchParams: Promise<IProductParams>; // wrapped into Promise<>
}

export default async function Home({ searchParams }: HomeProps) {
  const { category, searchTerm } = await searchParams; // await added

  // Fetch products from the server
  const products = await getProducts({ category, searchTerm });

  if (products.length === 0) {
    return <NullData title="OOPS ! No Products Found" />;
  }

  return (
    <div className="p-8">
      <Container>
        <div className="pb-8">
          <HomeBanner />
        </div>
        {/* Directly render the Client Component */}
        <ShuffledProducts products={products} />
      </Container>
    </div>
  );
}

您也可以从 docs 调用特殊的 cli 命令来自动执行此操作,而不是手动进行此类重构:

npx @next/codemod@canary upgrade latest

Next.js 抱怨的另一个问题

客户端组件尚不支持 async/await

可能是因为您导出服务器功能getproducts而没有使用

'use server'
指令

只需将

'use server'
添加到文件顶部即可:

'use server'; // << ADD THIS
import prisma from "@/libs/prismadb";
export interface IProductParams {
  category?: string | null;
  searchTerm?: string | null;
}

export default async function getproducts(params: IProductParams) {
  try {
    const { category, searchTerm } = params;
    let searchString = searchTerm;
... other code
© www.soinside.com 2019 - 2024. All rights reserved.