Next.js 13实验性App目录动态路由生成问题求助
Next.js 13 App Router 狗狗救助站动态路由问题解决方案
问题背景
开发非营利性狗狗救助站网站,使用Next.js 13实验性App目录搭配@apollo/client和GraphQL实现狗狗列表动态路由。点击列表链接进入详情页时,dog变量显示为undefined,仅动态路由页面出现错误,旧版Next.js可正常实现但不想回退版本。
错误原因分析
- API不兼容:App Router不支持Pages Router的
getStaticProps和getStaticPathsAPI,这两个方法在App Router中已被废弃。 - 导入路径错误:动态路由页面中错误导入了
@/libs/graphql(应为@/libs/client)和@/graphql/perritos(应为@/graphql/dogs),导致数据获取失败。 - 客户端组件限制:错误给页面添加
"use client"指令,若无需客户端交互,服务器组件更适合数据获取场景,且客户端组件无法直接通过旧API接收服务器端生成的props。
修复步骤及代码示例
1. 修正导入路径
确保动态路由页面的导入路径与实际文件结构一致:
- 替换
import { client } from "@/libs/graphql";为import { client } from "@/libs/client"; - 替换
import { GET_DOGGIES, GET_DOG } from "@/graphql/perritos";为import { GET_DOGGIES, GET_DOG } from "@/graphql/dogs";
2. 替换静态生成API
使用App Router的generateStaticParams替代getStaticPaths,并在服务器组件内部异步获取数据(替代getStaticProps)。
修改后的./app/dogs/[slug]/page.jsx代码:
import { client } from "@/libs/client"; import { GET_DOGGIES, GET_DOG } from "@/graphql/dogs"; // 生成静态路由路径,替代原getStaticPaths export async function generateStaticParams() { const { data } = await client.query({ query: GET_DOGGIES, }); return data.dogs.data.map((d) => ({ slug: d.attributes.slug, })); } // 服务器组件异步获取数据并渲染 export default async function Doggie({ params }) { const { data } = await client.query({ query: GET_DOG, variables: { slug: params.slug }, }); const dog = data.dog.data; // 空值判断避免报错 if (!dog) { return <div>狗狗不存在</div>; } return ( <div> <h1>{dog.attributes.name}</h1> <p>{dog.attributes.desc}</p> </div> ); }
3. (可选)支持客户端交互
若页面需要客户端交互逻辑(如点击事件、状态管理),可拆分服务器组件与客户端组件:
服务器组件./app/dogs/[slug]/page.jsx
import { client } from "@/libs/client"; import { GET_DOGGIES, GET_DOG } from "@/graphql/dogs"; import DoggieClient from "./DoggieClient"; export async function generateStaticParams() { const { data } = await client.query({ query: GET_DOGGIES, }); return data.dogs.data.map((d) => ({ slug: d.attributes.slug, })); } export default async function Doggie({ params }) { const { data } = await client.query({ query: GET_DOG, variables: { slug: params.slug }, }); const dog = data.dog.data; if (!dog) { return <div>狗狗不存在</div>; } // 将数据传递给客户端组件 return <DoggieClient dog={dog} />; }
客户端组件./app/dogs/[slug]/DoggieClient.jsx
"use client"; export default function DoggieClient({ dog }) { // 在此添加客户端交互逻辑,如按钮点击、状态管理等 return ( <div> <h1>{dog.attributes.name}</h1> <p>{dog.attributes.desc}</p> </div> ); }
内容的提问来源于stack exchange,提问作者Afx Crush
相关产品推荐
相关产品推荐

