本文详解如何在 next.js 应用中结合 userouter 与 useswr,根据 query 参数(如 ?filter=completed)动态请求并渲染外部 rest api 数据,实现无刷新筛选、自动缓存与响应式更新。
本文详解如何在 next.js 应用中结合 userouter 与 useswr,根据 query 参数(如 ?filter=completed)动态请求并渲染外部 rest api 数据,实现无刷新筛选、自动缓存与响应式更新。
在 Next.js 中构建具备筛选能力的数据列表页(如职位管理页),关键在于将 UI 交互(按钮点击)与路由状态、数据获取逻辑解耦且协同工作。核心思路是:让 URL 查询参数成为数据请求的唯一可信源(source of truth),借助 useRouter 管理导航,useSWR 基于变化的 key 自动触发重新请求与缓存复用。
以下是一个生产就绪的实现方案:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
✅ 正确的数据获取与路由联动
import axios from '@/lib/axios';
import useSWR from 'swr';
import { useRouter } from 'next/router';
const Jobs = () => {
const router = useRouter();
const { filter } = router.query;
// 定义 fetcher:统一处理 axios 响应结构
const fetcher = (url: string) =>
axios.get(url).then((res) => res.data.data);
// SWR key 动态依赖 filter —— 当 filter 改变时,key 变更,自动 revalidate
const { data: jobsData, error, isLoading } = useSWR(
filter ? `/jobs?filter=${encodeURIComponent(filter)}` : '/jobs',
fetcher
);
// 点击按钮时更新 URL,不触发页面刷新
const handleFilterClick = (newFilter: string) => {
router.push({
pathname: '/jobs',
query: { filter: newFilter },
});
};
// 渲染加载、错误与数据状态
if (isLoading) return <p>Loading jobs...</p>;
if (error) return <p className="text-red-500">Failed to load jobs.</p>;
return (
<div className="space-y-4">
{/* 筛选按钮组 */}
<div className="flex gap-2">
<button
onClick={() => handleFilterClick('completed')}
className={`px-4 py-2 rounded ${filter === 'completed' ? 'bg-blue-600 text-white' : 'bg-gray-200'}`}
>
Completed
</button>
<button
onClick={() => handleFilterClick('upcoming')}
className={`px-4 py-2 rounded ${filter === 'upcoming' ? 'bg-blue-600 text-white' : 'bg-gray-200'}`}
>
Upcoming
</button>
<button
onClick={() => handleFilterClick('cancelled')}
className={`px-4 py-2 rounded ${filter === 'cancelled' ? 'bg-blue-600 text-white' : 'bg-gray-200'}`}
>
Cancelled
</button>
<button
onClick={() => router.push('/jobs')} // 清除 filter
className="px-4 py-2 text-gray-600 hover:text-gray-900"
>
All
</button>
</div>
{/* 数据列表 */}
{jobsData && jobsData.length > 0 ? (
<ul className="space-y-3">
{jobsData.map((job) => (
<li key={job.id} className="p-4 border rounded bg-white shadow-sm">
<h3 className="font-medium">{job.title}</h3>
<p className="text-sm text-gray-600">Status: {job.status}</p>
</li>
))}
</ul>
) : (
<p className="text-gray-500 italic">No jobs found.</p>
)}
</div>
);
};
export default Jobs;⚠️ 关键注意事项
- URL 编码安全:使用 encodeURIComponent(filter) 防止特殊字符(如空格、&)破坏查询字符串结构;
- SWR Key 的确定性:确保 SWR key 是纯字符串且可序列化;避免传入对象或函数;
- 服务端渲染兼容性:该方案在 CSR(客户端渲染)下表现最佳;若需 SSR 支持,应配合 getServerSideProps 或使用 useSWR 的 ssr: true 选项(需 Next.js 13+ App Router 配合 fetcher 兼容服务端环境);
- 缓存与去重优化:SWR 默认对相同 key 复用缓存;不同 filter 值对应独立缓存,用户切换时秒级返回;
- 清除筛选:提供 “All” 按钮清空 filter,使 SWR 回退到基础 /jobs 请求,体现状态完整性。
通过此模式,你不仅实现了干净的 UI 筛选体验,还获得了 SWR 提供的自动轮询、错误重试、焦点重验证等高级能力,真正践行了 Next.js “数据即配置”的现代 React 开发范式。

















