You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14 App Router:如何在查询参数中存储多值筛选条件

在Next.js 14 App Router中实现筛选条件同步到查询参数

客户端组件处理交互与参数更新

在客户端组件中,使用next/navigation提供的useSearchParams和useRouter来读取和修改查询参数,实现筛选状态与URL的同步:

import { useSearchParams, useRouter } from 'next/navigation';

export default function ProductFilters() {
  const searchParams = useSearchParams();
  const router = useRouter();

  // 从查询参数解析已选中的筛选条件
  const selectedBrands = searchParams.get('brands')?.split(',') || [];
  const selectedCountries = searchParams.get('countries')?.split(',') || [];

  // 品牌选择切换逻辑
  const toggleBrand = (brand) => {
    const updatedBrands = selectedBrands.includes(brand)
      ? selectedBrands.filter(b => b !== brand)
      : [...selectedBrands, brand];
    
    const newParams = new URLSearchParams(searchParams);
    // 有选中品牌则设置参数,否则删除该参数
    updatedBrands.length 
      ? newParams.set('brands', updatedBrands.join(',')) 
      : newParams.delete('brands');

    // 更新路由,保留其他查询参数
    router.push(`/products?${newParams.toString()}`, { scroll: false });
  };

  // 国家选择切换逻辑(与品牌逻辑一致)
  const toggleCountry = (country) => {
    const updatedCountries = selectedCountries.includes(country)
      ? selectedCountries.filter(c => c !== country)
      : [...selectedCountries, country];
    
    const newParams = new URLSearchParams(searchParams);
    updatedCountries.length 
      ? newParams.set('countries', updatedCountries.join(',')) 
      : newParams.delete('countries');

    router.push(`/products?${newParams.toString()}`, { scroll: false });
  };

  return (
    <div className="filters-container">
      <div>
        <h3>品牌</h3>
        {['brand1', 'brand2', 'brand3'].map(brand => (
          <label key={brand} className="filter-item">
            <input
              type="checkbox"
              checked={selectedBrands.includes(brand)}
              onChange={() => toggleBrand(brand)}
            />
            {brand}
          </label>
        ))}
      </div>
      <div>
        <h3>国家</h3>
        {['spain', 'france', 'germany'].map(country => (
          <label key={country} className="filter-item">
            <input
              type="checkbox"
              checked={selectedCountries.includes(country)}
              onChange={() => toggleCountry(country)}
            />
            {country}
          </label>
        ))}
      </div>
    </div>
  );
}

服务器组件读取查询参数并获取数据

在服务器组件(如app/products/page.js)中,直接通过searchParams props获取查询参数,解析后用于数据筛选:

// app/products/page.js
import ProductFilters from './ProductFilters';
import ProductList from './ProductList';

export default async function ProductsPage({ searchParams }) {
  // 解析筛选参数,默认空数组
  const brands = searchParams.brands?.split(',') || [];
  const countries = searchParams.countries?.split(',') || [];

  // 根据筛选条件获取产品数据(替换为实际API请求)
  const products = await fetchFilteredProducts(brands, countries);

  return (
    <div className="products-page">
      <ProductFilters />
      <ProductList products={products} />
    </div>
  );
}

// 模拟数据请求函数
async function fetchFilteredProducts(brands, countries) {
  const query = new URLSearchParams();
  if (brands.length) query.set('brands', brands.join(','));
  if (countries.length) query.set('countries', countries.join(','));

  const res = await fetch(`/api/products?${query.toString()}`, { next: { revalidate: 60 } });
  if (!res.ok) throw new Error('Failed to fetch products');
  return res.json();
}

关键注意事项

  • 空参数处理:当没有选中项时,删除对应的查询参数,避免URL出现无效的空参数(如?brands=)。
  • 路由跳转优化:使用{ scroll: false }参数,避免筛选切换时页面滚动到顶部,提升用户体验。
  • 参数解析兼容:处理searchParams.brands为undefined的情况,避免调用split时出错。

内容的提问来源于stack exchange,提问作者Chicha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:05:08