
在 Next.js App Router 中,useRouter().query 已被弃用,直接解构 router.query.id 会报错;应改用 useParams() 获取动态段参数,这是官方推荐且稳定可靠的方式。
在 next.js app router 中,`userouter().query` 已被弃用,直接解构 `router.query.id` 会报错;应改用 `useparams()` 获取动态段参数,这是官方推荐且稳定可靠的方式。
Next.js 13+ 的 App Router(即 app/ 目录结构)与旧版 Page Router(pages/)在路由参数获取机制上有根本性差异。你当前的项目结构为 app/shop/[id]/page.tsx,明确属于 App Router 体系,因此不能使用 next/router 或依赖 router.query——该对象在 App Router 中始终为 undefined,强行解构必然触发 TypeError: Cannot destructure property 'id' of 'router.query' as it is undefined。
✅ 正确做法:使用 useParams() HookuseParams() 是 App Router 专用 Hook,专用于读取动态路由段(如 [id]、[slug])的值,返回一个包含所有命名段的键值对对象,类型安全且服务端/客户端均可使用。
以下是修复后的完整示例代码:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
// app/shop/[id]/page.tsx
"use client";
import { useState, useEffect } from 'react';
import { useParams } from 'next/navigation'; // ✅ 正确导入
export default function ShopPage() {
const [shopData, setShopData] = useState<any>(null);
const { id } = useParams(); // ✅ 安全获取 id,类型自动推导为 string | string[]
useEffect(() => {
const fetchData = async () => {
if (!id) return; // ✅ id 可能为 string[](如多级嵌套),建议校验
// 若确保单值,可显式转换
const shopId = Array.isArray(id) ? id[0] : id;
try {
const response = await fetch(`/api/shop/${encodeURIComponent(shopId)}`);
if (response.ok) {
const result = await response.json();
setShopData(result.shop);
} else {
console.error('Failed to fetch shop:', response.statusText);
}
} catch (error) {
console.error('Error fetching shop:', error);
}
};
fetchData();
}, [id]); // ✅ 依赖项包含 id,确保路由变化时重新请求
if (!id) return <div>Loading...</div>;
if (!shopData) return <div>Finding shop details...</div>;
return (
<div>
<h1>Shop ID: {shopData.id}</h1>
<p>{shopData.name}</p>
</div>
);
}⚠️ 注意事项:
-
useParams()返回的id类型为string | string[],当路径为/shop/123时通常为string,但在某些嵌套路由或重写场景下可能为数组,建议做类型判断或使用Array.isArray(id) ? id[0] : id安全取值; - 不要混用
next/router(Page Router 专属)和next/navigation(App Router 专属),否则将导致运行时错误或useRouter is not mounted; - 动态参数无需手动解析 URL 或监听
usePathname()——useParams()更精准、语义更清晰,且支持服务端组件(SSR/SSG); - 若需在服务端组件(如不加
"use client"的page.tsx)中获取参数,可直接通过async组件参数接收:async function ShopPage({ params }: { params: { id: string } })—— 这是 App Router 的首选服务端方案。
总结:拥抱 App Router 的范式升级,用 useParams() 替代 router.query,既规避运行时错误,又提升代码可维护性与类型安全性。


















