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
相关产品推荐
相关产品推荐

