Next.js 14项目中如何通过Strapi实现单/多分类筛选?
实现Next.js 14 + Strapi 博客分类筛选方案
1. 明确组件分工与类型
- 页面组件(
page.js):保持服务端组件,负责根据URL参数获取对应分类的博客数据。 - 分类按钮组件(
CategoryFilters.jsx):改为客户端组件(添加'use client'指令),处理点击交互并更新URL参数。 - 博客列表组件(
BlogList.jsx):可作为服务端/客户端组件,接收博客数据并渲染。
2. 修改fetchBlogs函数,支持分类筛选参数
Strapi的过滤查询语法为filters[字段名][$eq]=值,我们需要把分类参数转换成对应的查询字符串:
const fetchBlogs = async (category) => { const reqOptions = { headers: { Authorization: `Bearer ${process.env.API_TOKEN}`, }, }; // 构建查询参数:如果有分类则添加过滤条件,否则只保留populate=* let queryParams = 'populate=*'; if (category) { queryParams += `&filters[category][$eq]=${encodeURIComponent(category)}`; } const request = await fetch(`${config.api}/api/blogs?${queryParams}`, reqOptions); const response = await request.json(); return response; };
3. 改造页面组件,根据URL参数获取对应数据
在服务端页面组件中,通过searchParams获取当前选中的分类,传递给fetchBlogs:
// app/blogs/page.js import fetchBlogs from '@/lib/fetchBlogs'; import CategoryFilters from '@/components/CategoryFilters'; import BlogList from '@/components/BlogList'; export default async function BlogsPage({ searchParams }) { // 从URL的searchParams中获取当前分类,默认空(显示全部) const selectedCategory = searchParams?.category || ''; const blogs = await fetchBlogs(selectedCategory); return ( <div className="container"> {/* 传递当前选中的分类给按钮组件,用于高亮 */} <CategoryFilters activeCategory={selectedCategory} /> <BlogList blogs={blogs.data} /> </div> ); }
4. 实现分类按钮客户端组件
使用Next.js的useRouter或useSearchParams来更新URL的category参数,触发页面重新获取数据:
// components/CategoryFilters.jsx 'use client'; import { useRouter, useSearchParams } from 'next/navigation'; // 假设分类列表从Strapi获取,或者硬编码(实际项目建议从Strapi获取分类数据) const categories = ['前端', '后端', '设计', '产品']; export default function CategoryFilters({ activeCategory }) { const router = useRouter(); const searchParams = useSearchParams(); const handleFilterClick = (category) => { const newSearchParams = new URLSearchParams(searchParams); if (category === activeCategory) { // 点击已选中的分类,移除筛选条件(显示全部) newSearchParams.delete('category'); } else { // 设置选中的分类 newSearchParams.set('category', category); } // 更新URL,触发服务端组件重新获取数据 router.push(`/blogs?${newSearchParams.toString()}`); }; return ( <div className="filter-buttons"> {categories.map((cat) => ( <button key={cat} onClick={() => handleFilterClick(cat)} className={`filter-btn ${activeCategory === cat ? 'active' : ''}`} > {cat} </button> ))} </div> ); }
5. 可选:从Strapi动态获取分类列表
如果分类是在Strapi中维护的,可在页面组件中额外获取分类数据,传递给按钮组件:
// 在BlogsPage中添加 const fetchCategories = async () => { const reqOptions = { headers: { Authorization: `Bearer ${process.env.API_TOKEN}`, }, }; const res = await fetch(`${config.api}/api/categories`, reqOptions); return res.json(); }; // 同时获取博客和分类数据 const [blogsRes, categoriesRes] = await Promise.all([ fetchBlogs(selectedCategory), fetchCategories() ]); // 传递给组件 <CategoryFilters activeCategory={selectedCategory} categories={categoriesRes.data.map(cat => cat.attributes.name)} />
关键调整点总结
- 客户端组件标记:分类按钮组件必须加
'use client',因为涉及交互事件。 - Strapi查询语法:用
filters[category][$eq]=分类值实现精确匹配筛选,如需模糊匹配可改用$contains。 - URL参数传递:通过
searchParams在服务端组件和客户端组件间传递筛选状态,保证刷新页面后筛选状态不丢失。 - 路由更新:使用
router.push更新URL参数,触发服务端组件重新执行fetchBlogs获取对应数据。
内容的提问来源于stack exchange,提问作者mdnc
相关产品推荐
相关产品推荐

