Next13 App Router报错:类型'AppRouterInstance'不存在'query'属性
问题分析
Next.js 13 App Router 中,从 next/navigation 导入的 useRouter 和旧版 Pages Router 的 useRouter 完全不同——前者没有 query 属性,所以你写 const { query } = router 必然触发类型错误。
解决方案
方法1:客户端组件用 useParams 取动态参数
你的页面加了 'use client' 标记属于客户端组件,直接用 Next.js 提供的 useParams 钩子就能拿到动态路由里的 id:
- 导入
useParams:
import { useParams } from 'next/navigation';
- 替换原路由相关代码:
// 删除这两行: // const router = useRouter(); // const { query } = router; // 替换为: const params = useParams(); const id = params.id as string; // useParams返回值为string | string[],需断言为string类型
修改后的完整客户端组件代码:
'use client'; import { useParams } from 'next/navigation'; import { useEffect } from 'react'; import data from '../../../data.json'; import React from 'react'; export default function Work() { const params = useParams(); const id = params.id as string; useEffect(() => { console.log(data.portfolioData); }, []); const item = data.portfolioData.find((item) => item.id.toString() === id); if (!item) { return <div>Loading...</div>; } return ( <main className="min-h-screen bg-secondary"> <section> <div style={{ backgroundImage: `url("/images/text-bg.png")`, backgroundSize: 'cover', backgroundPosition: 'center', backgroundRepeat: 'no-repeat', }} ></div> </section> <div className="xl:container mx-auto px-4 sm:px-6 xl:px-0"> <h1 className="mt-12 text-3xl font-bold font-termina text-primary mb-6 text-center sm:text-left"> <span className="font-light">MY</span> <br />DESIGNS </h1> <div className="bg-accent p-4 card"> {/* 这里建议渲染单个匹配的item详情,原代码遍历所有数据是错误的 */} <div className="rounded-lg w-auto bg-accent relative transform hover:scale-105 hover:rotate-1 transition-all duration-500 shadow-2xl"> <img className="rounded-lg" src={item.thumbnail} alt={item.title} /> <div className="rounded-lg absolute inset-0 flex flex-col items-center justify-center opacity-0 hover:opacity-100 transition-opacity duration-500 bg-black bg-opacity-70"> <h3 className="text-md font-termina font-semibold text-white">{item.title}</h3> </div> </div> </div> </div> </main> ); }
方法2:改成服务器组件(更推荐)
如果页面不需要客户端交互,可去掉 'use client' 标记,直接在服务器组件中接收 params 参数——这是 App Router 最佳实践,性能更优:
// 移除'use client',转为服务器组件 import data from '../../../data.json'; // 直接从组件参数获取动态路由params export default function Work({ params }: { params: { id: string } }) { const item = data.portfolioData.find((item) => item.id.toString() === params.id); if (!item) { return <div>Loading...</div>; } return ( <main className="min-h-screen bg-secondary"> <section> <div style={{ backgroundImage: `url("/images/text-bg.png")`, backgroundSize: 'cover', backgroundPosition: 'center', backgroundRepeat: 'no-repeat', }} ></div> </section> <div className="xl:container mx-auto px-4 sm:px-6 xl:px-0"> <h1 className="mt-12 text-3xl font-bold font-termina text-primary mb-6 text-center sm:text-left"> <span className="font-light">MY</span> <br />DESIGNS </h1> <div className="bg-accent p-4 card"> <div className="rounded-lg w-auto bg-accent relative transform hover:scale-105 hover:rotate-1 transition-all duration-500 shadow-2xl"> <img className="rounded-lg" src={item.thumbnail} alt={item.title} /> <div className="rounded-lg absolute inset-0 flex flex-col items-center justify-center opacity-0 hover:opacity-100 transition-opacity duration-500 bg-black bg-opacity-70"> <h3 className="text-md font-termina font-semibold text-white">{item.title}</h3> </div> </div> </div> </div> </main> ); }
注意:若页面需要客户端交互(如点击事件、状态管理),再用客户端组件方案;否则优先用服务器组件,无需导入路由钩子,代码更简洁,还能在服务器端完成数据匹配,减少客户端计算。
内容的提问来源于stack exchange,提问作者Chris Barnett
相关产品推荐
相关产品推荐

