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

Next.js Header组件React Hooks使用报错及async/await问题求助

问题分析与解决方案

报错原因

你遇到的错误本质是:Next.js中,客户端组件(标记'use client')不能直接接收由服务端异步组件生成的children内容。虽然仅在HeaderContainer添加了客户端标记,但父组件Header是异步服务端组件,它将自身异步渲染的导航内容作为children传递给HeaderContainer,这会触发客户端组件处理异步内容的冲突报错。


修复方案(两种可选)

方案一:拆分组件,分离数据渲染与客户端交互

将数据获取、导航渲染逻辑抽成独立的服务端组件,再在客户端容器组件中调用它。

  1. 创建服务端组件HeaderContent.js
// components/HeaderContent.js
import Link from 'next/link'
import Image from 'next/image'
import { GET_HEADER, getInfo } from '@/api/api'
import Submenu from './parts/Submenu'
import Burguer from './parts/Burguer'

export default async function HeaderContent() {
  const info = await getInfo(GET_HEADER)
  if (info === null || info === undefined) return null
  const dataHead = info.data?.header.data.attributes.links || []

  return (
    <>
      <ul className='flex lg:hidden justify-between px-4 items-center'>
        <Link href='/'>
          <Image
            src='/images/logo.svg'
            width='140'
            height='140'
            alt='LogoHeader'
          />
        </Link>
        <Burguer dropdown={dataHead} />
      </ul>
      <ul className='hidden lg:flex justify-around items-center px-6'>
        {dataHead.map((link, i) => {
          const { title, href, index, dropdown, external_link } = link

          if (index) {
            return (
              <Link key={i} href={href}>
                <Image
                  src='/images/logo.svg'
                  width={150}
                  height={150}
                  alt='LogoHeader'
                />
              </Link>
            )
          }

          if (dropdown.length > 0) {
            return <Submenu key={i} title={title} dropdown={dropdown} />
          }

          return (
            <Link
              key={i}
              href={href ? href : ''}
              className='text-white hover:text-gray-300 transition duration-300'
              target={external_link ? '_blank' : '_self'}
            >
              {title}
            </Link>
          )
        })}
      </ul>
    </>
  )
}
  1. 修改客户端组件HeaderContainer.js
// components/parts/HeaderContainer.js
'use client'
import { useState, useEffect } from 'react'
import HeaderContent from '../HeaderContent'

const HeaderContainer = () => {
  const [scrolled, setScrolled] = useState(false)

  useEffect(() => {
    const handleScroll = () => {
      setScrolled(window.scrollY > 50)
    }

    window.addEventListener('scroll', handleScroll)
    // 初始化时检查滚动位置,避免样式异常
    handleScroll()

    return () => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [])

  return (
    <header
      className={`${
        scrolled ? 'py-10 lg:py-8' : 'py-16 lg:py-14'
      } fixed top-[-0.25rem] lg:top-0 lg:ml-[-1rem] bg-[url(/images/menu_desktop.svg)] bg-no-repeat text-xl bg-cover bg-center w-screen lg:w-[105%] z-[500] transition-all duration-300`}
    >
      <nav className='container mx-auto'>
        <HeaderContent />
      </nav>
    </header>
  )
}

export default HeaderContainer
  1. 简化原Header.js
// components/Header.js
import HeaderContainer from './parts/HeaderContainer'

export default function Header() {
  return <HeaderContainer />
}

方案二:将数据作为Props传递给客户端组件

在服务端组件中获取数据后,直接将数据传递给客户端组件,由客户端组件负责渲染导航内容。

  1. 修改服务端组件Header.js
// components/Header.js
import { GET_HEADER, getInfo } from '@/api/api'
import HeaderContainer from './parts/HeaderContainer'

export default async function Header() {
  const info = await getInfo(GET_HEADER)
  if (info === null || info === undefined) return null
  const dataHead = info.data?.header.data.attributes.links || []

  return <HeaderContainer dataHead={dataHead} />
}
  1. 修改客户端组件HeaderContainer.js
// components/parts/HeaderContainer.js
'use client'
import { useState, useEffect } from 'react'
import Link from 'next/link'
import Image from 'next/image'
import Submenu from './Submenu'
import Burguer from './Burguer'

const HeaderContainer = ({ dataHead }) => {
  const [scrolled, setScrolled] = useState(false)

  useEffect(() => {
    const handleScroll = () => {
      setScrolled(window.scrollY > 50)
    }

    window.addEventListener('scroll', handleScroll)
    handleScroll()

    return () => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [])

  return (
    <header
      className={`${
        scrolled ? 'py-10 lg:py-8' : 'py-16 lg:py-14'
      } fixed top-[-0.25rem] lg:top-0 lg:ml-[-1rem] bg-[url(/images/menu_desktop.svg)] bg-no-repeat text-xl bg-cover bg-center w-screen lg:w-[105%] z-[500] transition-all duration-300`}
    >
      <nav className='container mx-auto'>
        <ul className='flex lg:hidden justify-between px-4 items-center'>
          <Link href='/'>
            <Image
              src='/images/logo.svg'
              width='140'
              height='140'
              alt='LogoHeader'
            />
          </Link>
          <Burguer dropdown={dataHead} />
        </ul>
        <ul className='hidden lg:flex justify-around items-center px-6'>
          {dataHead.map((link, i) => {
            const { title, href, index, dropdown, external_link } = link

            if (index) {
              return (
                <Link key={i} href={href}>
                  <Image
                    src='/images/logo.svg'
                    width={150}
                    height={150}
                    alt='LogoHeader'
                  />
                </Link>
              )
            }

            if (dropdown.length > 0) {
              return <Submenu key={i} title={title} dropdown={dropdown} />
            }

            return (
              <Link
                key={i}
                href={href ? href : ''}
                className='text-white hover:text-gray-300 transition duration-300'
                target={external_link ? '_blank' : '_self'}
              >
                {title}
              </Link>
            )
          })}
        </ul>
      </nav>
    </header>
  )
}

export default HeaderContainer

额外优化建议

  • 添加transition-all duration-300类,让Header内边距变化更平滑
  • 初始化时调用handleScroll,避免页面加载时滚动位置已超过阈值但样式未更新的问题

内容的提问来源于stack exchange,提问作者Manuel Esteban Morales Zuarez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 20:07:03