Next.js动态Slug组件导入JS对象列表及取值异常排查
Next.js动态路由项目详情页undefined报错解决
问题分析
核心问题是服务端渲染(SSR)阶段router.query.slug未初始化,导致:
- VS Code终端(服务端)打印
project为undefined:服务端渲染时无客户端路由信息,router.query.slug为空,转数字后得到NaN,projectlist[NaN]无法匹配到对应项目 - 浏览器控制台能显示项目详情:客户端hydration完成后,路由信息加载完毕,
projectid正确获取,可匹配到对应项目 - 访问
project.name时报错:服务端渲染阶段project为undefined,读取其属性触发TypeError
另外ProjectDetail组件的参数解构存在语法错误,会影响参数的正确接收。
解决方案
1. 修正组件参数解构语法
将错误的参数解构写法改为正确形式:
// 错误写法 const ProjectDetail = ({projectid}=props) => { ... } // 正确写法二选一: // 写法1:直接解构参数 const ProjectDetail = ({ projectid }) => { ... } // 写法2:先接收props再解构 const ProjectDetail = (props) => { const { projectid } = props; ... }
2. 等待路由就绪后渲染详情组件
在ProjectPage中利用router.isReady判断路由是否初始化完成,避免服务端渲染时传递无效的projectid:
import { useRouter } from 'next/router'; import ProjectDetail from '../../components/projectdetails'; import '../../styles/globals.css' const ProjectPage = () => { const router = useRouter(); // 路由未就绪时,返回加载提示 if (!router.isReady) { return <div>加载中...</div>; } const projectid = parseInt(router.query.slug, 10); return ( <> <ProjectDetail projectid={projectid} /> </> ); }; export default ProjectPage;
3. 给ProjectDetail添加空值保护
即使路由就绪,也要处理projectid对应项目不存在的情况,避免报错:
'use client'; import { Box, Paper, Typography } from '@mui/material'; import projectlist from '../utility/projectlist'; const ProjectDetail = ({ projectid }) => { const project = projectlist[projectid]; // 项目不存在时返回提示 if (!project) { return <div>项目不存在</div>; } console.log(project.name); // const images = [...project.screenshot]; return ( <div> <Box> <Typography variant="h4">{project.name}</Typography> {/* 渲染其他项目内容 */} </Box> </div> ); }; export default ProjectDetail;
4. 进阶方案:使用静态预渲染(推荐)
如果项目列表是静态数据,用getStaticPaths和getStaticProps预渲染所有详情页,彻底避免路由初始化问题:
修改/pages/projects/[slug].js:
import ProjectDetail from '../../components/projectdetails'; import '../../styles/globals.css' import projectlist from '../../utility/projectlist'; // 生成所有可能的动态路由路径 export async function getStaticPaths() { const paths = projectlist.map((_, index) => ({ params: { slug: index.toString() }, })); return { paths, fallback: false }; } // 获取对应项目的数据 export async function getStaticProps({ params }) { const projectid = parseInt(params.slug, 10); const project = projectlist[projectid]; return { props: { project }, }; } const ProjectPage = ({ project }) => { if (!project) { return <div>项目不存在</div>; } return ( <> <ProjectDetail project={project} /> </> ); }; export default ProjectPage;
修改ProjectDetail组件直接接收project:
'use client'; import { Box, Paper, Typography } from '@mui/material'; const ProjectDetail = ({ project }) => { console.log(project.name); // const images = [...project.screenshot]; return ( <div> <Box> <Typography variant="h4">{project.name}</Typography> {/* 渲染其他项目内容 */} </Box> </div> ); }; export default ProjectDetail;
内容的提问来源于stack exchange,提问作者Ram Kumar
相关产品推荐
相关产品推荐

