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

Next.js 13 + Sanity组件调用报错:Cannot read properties of undefined (reading 'map')

解决Next.js中组件内getStaticProps失效导致的TypeError问题

问题概述

  • 背景:使用Sanity进行内容管理,在React项目中通过useState+useEffect执行GROQ查询可正常运行;迁移至Next.js 13后,发现getStaticProps仅在pages目录下的页面组件中生效。
  • 问题现象:将查询逻辑封装到AboutCheck组件(存放于component目录),并在pages/index.jsx中引入该组件时,触发错误:TypeError: Cannot read properties of undefined (reading 'map')。
  • 前置确认:GROQ查询本身可正常执行,仅在组件调用时出现错误。

核心原因

Next.js的getStaticProps(包括getServerSideProps、getStaticPaths)仅对pages目录下的页面组件生效,components目录下的组件中定义这些数据获取函数不会被Next.js框架执行。因此当在index.jsx中引入AboutCheck组件时,HeroSection props未被赋值,导致其为undefined,调用map方法时触发错误。

解决方案

方案一:将数据获取移至页面组件,通过props传递数据

将getStaticProps移到pages/index.jsx中执行数据查询,再将结果通过props传递给AboutCheck组件。

修改pages/index.jsx:

import Head from 'next/head'
import Image from 'next/image'
import { Inter } from 'next/font/google'
import styles from '@/styles/Home.module.css'
import AboutCheck from '@/component/AboutCheck'
import groq from "groq";
import createClient from "../client";

const inter = Inter({ subsets: ['latin'] })

function Home({ HeroSection }) {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <p>Hey</p>
      <AboutCheck HeroSection={HeroSection} />
    </>
  )
}

export async function getStaticProps() {
  const query = `*[_type == "HeroSection"]{
    heroheading,
    herosubheading,
    ctaButtonText,
    coverImage {
      asset -> {
        url
      }
    }
  }`;
  const HeroSection = await createClient.fetch(query);
  return {
    props: {
      HeroSection,
    },
  };
}

export default Home;

修改AboutCheck组件(仅保留UI渲染逻辑,增加空值判断):

const AboutCheck = ({ HeroSection }) => {
  // 空值判断避免数据未加载时出错
  if (!HeroSection) return <div>Loading...</div>;
  
  return (
    <div>
      {HeroSection.map((item) => (
        <li key={item._id}>{item.heroheading}</li>
      ))}
    </div>
  );
};

export default AboutCheck;

方案二:组件内客户端渲染获取数据

如果需要组件独立获取数据,可在组件内通过useEffect执行客户端查询,适合无需静态生成的场景:

import { useState, useEffect } from 'react';
import groq from "groq";
import createClient from "../client";

const AboutCheck = () => {
  const [HeroSection, setHeroSection] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      const query = `*[_type == "HeroSection"]{
        heroheading,
        herosubheading,
        ctaButtonText,
        coverImage {
          asset -> {
            url
          }
        }
      }`;
      const data = await createClient.fetch(query);
      setHeroSection(data);
      setLoading(false);
    };

    fetchData();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {HeroSection.map((item) => (
        <li key={item._id}>{item.heroheading}</li>
      ))}
    </div>
  );
};

export default AboutCheck;

方案三:使用Next.js 13 App Router的Server Component

如果项目采用Next.js 13+推荐的App Router(app目录),可将AboutCheck设为Server Component,直接在组件内编写异步数据获取逻辑:

// app/components/AboutCheck.jsx
import groq from "groq";
import createClient from "../../client";

async function AboutCheck() {
  const query = `*[_type == "HeroSection"]{
    heroheading,
    herosubheading,
    ctaButtonText,
    coverImage {
      asset -> {
        url
      }
    }
  }`;
  const HeroSection = await createClient.fetch(query);

  return (
    <div>
      {HeroSection.map((item) => (
        <li key={item._id}>{item.heroheading}</li>
      ))}
    </div>
  );
}

export default AboutCheck;

在app/page.jsx中直接引入该组件即可,无需额外传递props。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:17:48