You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14 App Router服务端与客户端组件混合使用报错求助

Next.js 14 App Router:服务端组件嵌套客户端组件报错问题

我当前使用Next.js v14及App Router,想实现服务端组件嵌套在客户端组件中的需求(官方文档说明支持这种嵌套方式):

<ClientComponent>
  <ServerComponent />
</ClientComponent>

但实际尝试后始终触发报错:async/await is not yet supported in Client Components, only Server Components。我的核心目标是在服务端组件AllBlogs中完成所有博客文章的获取,当前组件层级定义如下:

  • Layout: 服务端组件
  • StoryblokProvider: 客户端组件
  • Page: 服务端组件
  • BlogOverviewPage: 服务端组件
  • AllBlogs: 预期为服务端组件

组件树结构:Layout > StoryblokProvider > Page > BlogOverviewPage > AllBlogs


各组件代码

Layout组件

export default async function RootLayout({
  children,
  params: { locale },
}: Props) {
  return (
    <StoryblokProvider>
      <html lang={locale}>
        <body>
            {children}
        </body>
      </html>
    </StoryblokProvider>
  )
}

StoryblokProvider组件

/** 1. Tag it as a client component */
"use client"

import { apiPlugin, storyblokInit } from "@storyblok/react"

import { storyblokComponents } from "@/components/storyblok/storyblok-components"

/** 2. Initialize it as usual */
storyblokInit({
  accessToken: process.env.NEXT_PUBLIC_STORYBLOK_TOKEN,
  use: [apiPlugin],
  components: storyblokComponents,
})

const StoryblokProvider = ({ children }: { children: React.ReactNode }) => {
  return children
}

export default StoryblokProvider

Page组件

const Page = async ({ params }: Props) => {
  const { data } = await fetchData(params.slug)

  return (
    <>
      <CaptchaProvider>
        <StoryblokStory story={data.story} bridgeOptions={bridgeOptions} />
        <div id="pewl" />
      </CaptchaProvider>
    </>
  )
}

export default Page

async function fetchData(slug: string) {
  slug = slug ?? "home"

  if (Array.isArray(slug)) {
    slug = slug.join("/")
  }

  const storyblokApi: StoryblokClient = getStoryblokApi()
  return storyblokApi.getStory(slug)
}

AllBlogs组件

const AllBlogs = async () => {
  const blogs = await fetchAllBlogs()

  return blogs.map((blog: BlogPageStoryblok) => (
    <BlogCard blog={blog} key={blog.uuid} />
  ))
}

const fetchAllBlogs = cache(async () => {
  let sbParams: ISbStoriesParams = {
    starts_with: "blog",
  }

  const storyblokApi: StoryblokClient = getStoryblokApi()

  const { data } = await storyblokApi.get("cdn/stories/", sbParams)
  return data.stories.filter(
    (story: StoryblokStory<BlogPageStoryblok>) => !story.is_startpage
  )
})

尝试过的解决方法

我曾尝试将AllBlogs包裹在自定义的客户端组件中,但仍触发相同报错:

"use client"

export default function ClientComponent({
  children,
}: { children: React.ReactNode }) {
  return <> {children} </>
}
const BlogOverviewPage = ({ blok }: any) => {
  return (
    <ClientComponent>
      <AllBlogs />
    </ClientComponent>
  )
}

更新测试结果

如果在Page.tsx中用AllBlogs替换StoryblokStory,博客内容可以正常在服务端获取,但其他页面均无法正常工作:

const Page = async ({ params }: Props) => {
  const { data } = await fetchData(params.slug)

  return (
    <CaptchaProvider>
      <BlogOverviewPage blok={data.story} />
      {/*<StoryblokStory story={data.story} bridgeOptions={bridgeOptions} />*/}
      <div id="pewl" />
    </CaptchaProvider>
  )
}

export default Page

async function fetchData(slug: string) {
  slug = slug ?? "home"

  if (Array.isArray(slug)) {
    slug = slug.join("/")
  }

  const storyblokApi: StoryblokClient = getStoryblokApi()
  return storyblokApi.getStory(slug)
}

希望得到解决该报错的方案,实现服务端组件嵌套在客户端组件中获取博客的需求。


内容的提问来源于stack exchange,提问作者combi35

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:53:14