Next.js客户端组件使用async/await报错,求Prismadb分页解决方案
问题分析
错误原因很明确:标记了"use client"的客户端组件不能是async函数,也无法在组件渲染阶段直接使用await调用异步操作。你的StoreTable组件加了"use client"(因为要使用useProductPagination客户端状态钩子),但直接写成了async组件并awaitgetData,这违反了Next.js的客户端组件规则。
另外你的分页逻辑存在错误:prismadb.product.findMany里的skip和take参数写反了,正确的分页公式应该是:
take:每页显示的条数(对应你的perPage)skip:跳过的条数,计算方式为(page - 1) * perPage
解决方案
下面提供两种可行的调整方案,你可以根据项目情况选择:
方案一:使用useEffect + useState在客户端组件中获取数据
保留客户端组件的状态管理,通过副作用钩子异步调用Server Action:
1. 修改客户端组件代码
"use client"; import { Products, columns } from "@/app/store/columns"; import { DataTable } from "@/app/store/data-table"; import { getData } from "@/lib/store/get-product"; import { useProductPagination } from "@/lib/store/product-pagination"; import React, { useState, useEffect } from "react"; function StoreTable() { const { page, perPage } = useProductPagination(); const [data, setData] = useState<Products[]>([]); const [loading, setLoading] = useState(true); // 当page或perPage变化时,重新获取数据 useEffect(() => { const fetchData = async () => { setLoading(true); const result = await getData(perPage, page); setData(result); setLoading(false); }; fetchData(); }, [page, perPage]); if (loading) { return <div>加载中...</div>; } return ( <div className="w-screen pr-4 sm:pr-8 md:pr-10 max-w-7xl mx-auto"> <DataTable data={data} columns={columns} /> </div> ); } export default StoreTable;
2. 修正Server Action的分页逻辑
import { Products } from "@/app/store/columns"; import prismadb from "../prismadb"; export async function getData(perPage: number, page: number): Promise<Products[]> { const products = await prismadb.product.findMany({ // 修正skip和take的逻辑 skip: (page - 1) * perPage, take: perPage, }); return products.map((product, i) => ({ id: i + 1, name: product.name, description: product.description, category: product.category, origin: product.origin, sell: product.sellingPrice, purchase: product.purchasedPrice, amount: Math.random() * 100, status: product.status === "active" ? "active" : "inactive", })); }
方案二:使用SWR简化数据获取(推荐)
如果你的项目已经使用SWR,或者想要更简洁的缓存和重逻辑,可以用SWR来处理异步数据获取:
1. 安装SWR(如果没装的话)
npm install swr # 或 yarn add swr
2. 修改客户端组件
"use client"; import { Products, columns } from "@/app/store/columns"; import { DataTable } from "@/app/store/data-table"; import { getData } from "@/lib/store/get-product"; import { useProductPagination } from "@/lib/store/product-pagination"; import useSWR from "swr"; // 定义SWR的fetcher函数 const fetcher = async ([perPage, page]: [number, number]) => { return getData(perPage, page); }; function StoreTable() { const { page, perPage } = useProductPagination(); // 根据page和perPage作为key,自动触发数据获取 const { data, isLoading } = useSWR([perPage, page], fetcher); if (isLoading || !data) { return <div>加载中...</div>; } return ( <div className="w-screen pr-4 sm:pr-8 md:pr-10 max-w-7xl mx-auto"> <DataTable data={data} columns={columns} /> </div> ); } export default StoreTable;
3. 同样修正Server Action的分页逻辑(同方案一的第二步)
关键注意点
- 客户端组件不能是async函数,所有异步操作必须放到
useEffect、SWR/React Query这类工具中处理 - 分页逻辑一定要注意
skip和take的正确计算,否则会出现数据重复或缺失的问题 - Server Action本身是服务端运行的,不需要额外标记,确保它不在客户端组件的导入链中被强制客户端渲染(你的
getData目前没问题,因为它没有"use client"标记)
内容的提问来源于stack exchange,提问作者Mohammed Bekele
相关产品推荐
相关产品推荐

