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

Next.js+GraphQL博客getStaticPaths报undefined读取id错误

问题根因

你碰到的Cannot read property of undefined (reading 'id')是多个Next.js基础用法错误、变量引用错误共同导致的,直接触发点和关联问题如下:

  • getStaticPaths和getStaticProps用法完全混淆:getStaticPaths的作用是预生成所有动态路由的路径清单,它的入参不包含params属性,也不支持返回props。你在getStaticPaths里解构params并读取params.id时,params本身就是undefined,直接触发类型错误。你写的按参数查作者数据的逻辑,本来应该放在getStaticProps里。
  • 动态路由文件名是[slug].jsx,路由参数名是slug不是id,你之前多处代码取参数、写跳转链接都用id,和路由规则不匹配。
  • 页面组件内直接使用未定义的author、authors变量,就算数据请求成功也会触发变量未定义错误。
  • 作者列表组件的跳转链接使用了未定义的slug变量,点击跳转时会报错。
  • GraphQL按slug查询作者返回的是数组结构,你直接返回数组会导致后续页面取值逻辑出错。

分步修复方案

1. 修正services/index.js的请求逻辑

补全缺失的全量作者查询方法,调整单作者查询的返回值,直接返回匹配到的唯一作者对象:

export const getAuthorPosts = async (slug) => {
    const query = gql `
    query getAuthorPosts($slug: String!) {
        authors(where: {slug: $slug}) {
          bio
          name
          id
          slug
          photo {
            url
          }
          posts {
            createdAt
            slug
            title
            excerpt
            featuredImage {
              url
            }
          }
        }
      }
    `
    const results = await request(graphqlAPI, query, {slug})
    // 按slug查询唯一作者,直接返回第一个匹配项,补全返回slug字段
    return results.authors[0]
}

// 补全全量作者查询方法,用于生成静态路径
export const getAuthorProfile = async () => {
  const query = gql`
    query GetAllAuthors {
      authors {
        id
        slug
        name
        bio
        photo {
          url
        }
      }
    }
  `
  const results = await request(graphqlAPI, query)
  return results.authors
}

2. 重写pages/author/[slug].jsx逻辑

拆分getStaticPaths和getStaticProps的职责,修正组件的props接收和渲染逻辑:

import React from 'react'
import Link from 'next/link'
import { getAuthorPosts, getAuthorProfile } from '../../services'

const AuthorPosts = ({ author }) => {
  // 兜底逻辑,避免匹配不到作者时页面报错
  if (!author) return <div className="p-8 text-center">作者不存在</div>

  return (
    <div className="bg-white text-center shadow-lg rounded-lg p-8 mb-8">
      <h1 className="text-xl mb-8 font-semibold border-b pb-4">
      作者文章
      </h1>
      <div className="mb-8">
        <img 
          src={author.photo.url} 
          alt={author.name}
          className="w-24 h-24 rounded-full mx-auto object-cover mb-4"
        />
        <h4 className="text-lg font-medium border-b pb-4">{author.name}</h4>
        <p className="text-gray-600 mt-2">{author.bio}</p>
      </div>
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-5 p-0 lg:p-4 pb-6 mb-8">
        {author.posts.map((post) => (
            <div key={post.slug} className='bg-white rounded-lg shadow-xl p-4'>
                <div className="relative overflow-hidden shadow-md mb-6 h-48">
                    <img 
                    src={post.featuredImage.url} 
                    alt={post.title}
                    className="object-cover h-full w-full rounded-t-lg"
                    /> 
                </div>
                <h3 className='transition duration-100 text-center mb-4 cursor-pointer hover:text-pink-600 text-2xl font-semibold'>
                <Link href={`/post/${post.slug}`}>
                    {post.title}
                </Link>
                </h3>
                <p className="text-center text-lg text-gray-700 font-normal px-1 lg:px-2 mb-8">
                    {post.excerpt}
                </p>
                <div className="text-center mb-8">
                    <Link href={`/post/${post.slug}`}>
                    <span className="transition duration-500 transform hover:-translate-y-1 inline-block bg-pink-600 text-lg font-medium rounded-full text-white px-8 py-3 cursor-pointer">
                        阅读全文
                    </span>
                    </Link>
                </div>
            </div>
        ))}
      </div>
    </div>
  )
}

export default AuthorPosts

// getStaticPaths 仅负责生成所有需要预渲染的作者页路径
export async function getStaticPaths() {
  const authors = await getAuthorProfile()
  const paths = authors.map((author) => ({
    params: { slug: author.slug } // 路由参数名和[slug].jsx文件名保持一致
  }))

  return {
    paths,
    fallback: false // 未匹配的路径直接返回404
  }
}

// getStaticProps 负责获取当前路由对应的数据,传给页面组件
export async function getStaticProps({params}) {
  // 取params.slug,和动态路由参数名一致
  const author = await getAuthorPosts(params.slug)

  return {
    props:{ author }
  }
}

3. 修正components/author.jsx的跳转错误

修复未定义变量引用、跳转路径错误的问题:

import React, {useState, useEffect} from 'react'
import Link from 'next/link'
import { getAuthorProfile } from '../services'

const Authors = () => {
  const [authors, setAuthorProfile] = useState([]);

  useEffect(() => {
    getAuthorProfile()
      .then((newAuthors) =>setAuthorProfile(newAuthors))
  }, [])

  return (
    <div className="bg-white text-center shadow-lg rounded-lg p-8 mb-8">
      <h1 className="text-xl mb-8 font-semibold border-b pb-4">
      作者列表
      </h1>
      <div className="grid grid-cols-2 lg:grid-cols-4 gap-5 p-0 lg:p-4 pb-6 mb-8">
        {authors.map((author) => (
            <div key={author.id} className='bg-white rounded-lg shadow-xl'>
                <div className="relative overflow-hidden shadow-md mb-6 h-48">
                    <img 
                    src={author.photo.url} 
                    alt={author.name}
                    className="object-cover h-full w-full rounded-t-lg"
                    /> 
                </div>
                <h3 className='transition duration-100 text-center mb-4 cursor-pointer hover:text-pink-600 text-2xl font-semibold'>
                    {author.name}
                </h3>
                <p className="text-center text-lg text-gray-700 font-normal px-1 lg:px-2 mb-8">
                    {author.bio}
                </p>
                <div className="text-center mb-8">
                    {/* 从当前遍历的author对象中取slug,修正之前未定义变量的问题 */}
                    <Link href={`/author/${author.slug}`}>
                    <span className="transition duration-500 transform hover:-translate-y-1 inline-block bg-pink-600 text-lg font-medium rounded-full text-white px-8 py-3 cursor-pointer">
                        查看文章
                    </span>
                    </Link>
                </div>
            </div>
        ))}
      </div>
    </div>
  )
}

export default Authors

开发注意事项
  • Next.js动态路由中,getStaticPaths只负责返回预渲染路径列表,没有params入参,也不能返回props;页面数据获取逻辑必须放在getStaticProps或getServerSideProps中。
  • 动态路由的params字段名必须和文件名中括号内的参数名完全一致,文件命名为[slug].jsx时,只能通过params.slug获取参数。
  • 遍历列表渲染时,所有用到的字段必须从当前遍历项中取值,不能直接引用外层未定义的变量。
  • GraphQL按唯一条件查询返回的结果通常是数组结构,拿到结果后要先取匹配项再做后续逻辑,避免取值报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 14:36:28