NextJS14客户端组件用useState遇async/await不支持错误求助
问题解决:NextJS 14.03 客户端组件 async/await 报错
错误原因
你遇到的核心问题是客户端组件上下文被服务器组件污染:虽然给SectionGridHasMap加了"use client",但它导入的子组件(如Heading2、TabFilters、Pagination、EventCard)如果是未标记"use client"的服务器组件,Next.js会强制将整个SectionGridHasMap当作服务器组件处理。而服务器组件既不能使用useState这类客户端钩子,也不允许在组件上下文内触发异步逻辑冲突,最终导致报错。
解决方案
方案一:统一客户端组件标记
给所有被SectionGridHasMap导入的子组件顶部添加"use client"指令:
@/shared/Pagination.tsx@/shared/Heading2.tsx./TabFilters.tsx@/components/cards/event-card.tsx
客户端组件只能导入其他客户端组件,直接引用服务器组件会破坏Next.js的组件上下文隔离机制。
方案二:服务器端取数,props传递给客户端组件
将数据获取逻辑移到父页面(服务器组件,无需"use client"),再把数据通过props传给客户端组件,彻底避免客户端组件的异步取数冲突:
修改父页面src/app/(stay-listings)/listing-stay-map/page.tsx:
import React from "react"; import SectionGridHasMap from "../SectionGridHasMap"; const ListingStayMapPage = async () => { // 服务器组件顶层直接执行fetch,Next.js会自动优化请求 const res = await fetch("http://localhost:3000/api/events", { cache: "no-store", }); if (!res.ok) { throw new Error("Failed to fetch events"); } const { events } = await res.json(); return ( <div className="container pb-24 lg:pb-28 2xl:pl-10 xl:pr-0 xl:max-w-none"> <SectionGridHasMap events={events} /> </div> ); }; export default ListingStayMapPage;
修改子组件src/app/(stay-listings)/SectionGridHasMap.tsx:
"use client"; import React, { useState } from 'react'; import GoogleMapReact from 'google-map-react'; import Pagination from "@/shared/Pagination"; import TabFilters from "./TabFilters"; import Heading2 from "@/shared/Heading2"; import EventCard from "@/components/cards/event-card"; const defaultMapProps = { center: { lat: 59.95, lng: 30.33 }, zoom: 11 }; const SectionGridHasMap = ({ className = "", events: initialEvents }) => { // 用服务器端传来的数据初始化状态,后续可正常修改 const [events, setEvents] = useState(initialEvents || []); return ( <div className="relative flex min-h-screen"> <div className={`nc-SectionGridFilterCard flex-1 ${className}`} data-nc-id="SectionGridFilterCard"> <Heading2 /> <div className="mb-8 lg:mb-11"> <TabFilters /> </div> <div className="grid grid-cols-1 gap-6 md:gap-8 sm:grid-cols-2 lg:grid-cols-3"> {/* 优先用MongoDB文档的_id作为key,避免index导致的渲染问题 */} {events.map((event) => ( <EventCard key={event._id} event={event} /> ))} </div> <div className="flex mt-16 justify-center items-center"> <Pagination /> </div> </div> <div className="w-full h-full lg:w-1/2"> <GoogleMapReact bootstrapURLKeys={{ key: 'GOOGLE_MAPS_API_KEY' }} defaultCenter={defaultMapProps.center} defaultZoom={defaultMapProps.zoom} /> </div> </div> ); }; export default SectionGridHasMap;
额外检查
确保你的/api/events路由返回格式正确({ events: [...] }),且路由本身没有逻辑错误。
内容的提问来源于stack exchange,提问作者logan
相关产品推荐
相关产品推荐

