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

Next.js 13 App目录下服务端获取路由跳转后searchParams问题

问题

我正在开发一个基于Next.js 13 App目录的多语言应用,设有/products页面,需要通过URLSearchParams过滤页面数据。我单独创建了客户端过滤组件,通过如下方式跳转路由:http://localhost:3001/en/products?accessories=led-light--switch。我希望在服务端文件page.tsx中获取查询参数,根据文档可访问searchParams,但路由跳转后searchParams为空,仅刷新页面后才正常显示。如何在路由跳转后从服务端获取查询参数?

Filter组件代码

const onChangeHandler = (e: React.ChangeEvent) => {
  const { name, value, checked } = e.target;
  const newValues = checked ? [...checkBoxValues, value] : checkBoxValues.filter((val) => val !== value);

  setCheckBoxValues(newValues);

  if (newValues.length === 0) {
    params.delete(name); // 从params中移除整个'jobType'键
  } else {
    params.set(name, newValues.join("--")); // 为'jobType'键设置新值
  }

  router.push(pathname + (params.toString() ? "?" + params.toString() : ""));
};

page.tsx文件代码

export default async function IndexPage({
  params: { lang },
  searchParams,
}: {
  params: { lang: Locale };
  searchParams: any;
}) {
  const data = await getData(variables.apiUrls.product);

  const dictionary = await getDictionary(lang);
  let customMeta = {
    ...data.data.meta,
    title_en: data.data.meta.title_en.length > 0 ? data.data.meta.title_en : translateText(lang, data.data),
    title_bn: data.data.meta.title_bn.length > 0 ? data.data.meta.title_bn : translateText(lang, data.data),
  };

  return (
    <BaseLayout navigationType="others" lang={lang} meta={customMeta}>
      <ProductIndex lang={lang} dictionary={dictionary} />
    </BaseLayout>
  );
}
解决方案

问题核心是Next.js 13 App Router的客户端软导航默认不会触发服务端组件重新渲染,导致searchParams未更新,只有硬刷新才会重新拉取服务端数据。以下是三种可行解决方式:

方式一:强制触发服务端渲染

在router.push时添加配置,强制服务端组件重新渲染以获取最新查询参数:

router.push(
  pathname + (params.toString() ? "?" + params.toString() : ""),
  undefined,
  { forceOptimisticNavigation: true }
);

方式二:客户端处理过滤逻辑

既然过滤组件是客户端组件,可将数据过滤逻辑迁移到客户端:

  1. 服务端组件page.tsx获取全量产品数据,传递给客户端组件ProductIndex
  2. 在ProductIndex中用useSearchParams钩子获取实时查询参数,在客户端完成过滤

修改page.tsx

export default async function IndexPage({
  params: { lang },
  searchParams,
}: {
  params: { lang: Locale };
  searchParams: any;
}) {
  const data = await getData(variables.apiUrls.product);
  const dictionary = await getDictionary(lang);
  let customMeta = {
    ...data.data.meta,
    title_en: data.data.meta.title_en.length > 0 ? data.data.meta.title_en : translateText(lang, data.data),
    title_bn: data.data.meta.title_bn.length > 0 ? data.data.meta.title_bn : translateText(lang, data.data),
  };

  return (
    <BaseLayout navigationType="others" lang={lang} meta={customMeta}>
      <ProductIndex lang={lang} dictionary={dictionary} products={data.data.products} />
    </BaseLayout>
  );
}

修改ProductIndex客户端组件

'use client';

import { useSearchParams } from 'next/navigation';

export default function ProductIndex({ lang, dictionary, products }) {
  const searchParams = useSearchParams();
  
  // 根据查询参数过滤产品
  const filteredProducts = products.filter(product => {
    const accessories = searchParams.get('accessories');
    if (!accessories) return true;
    const accessoryList = accessories.split('--');
    return accessoryList.some(acc => product.accessories.includes(acc));
  });

  return (
    <div>
      {filteredProducts.map(product => (
        <div key={product.id}>{product.name}</div>
      ))}
    </div>
  );
}

方式三:触发服务端路径重新验证

在客户端跳转后调用revalidatePath,强制服务端重新获取最新参数并渲染:

'use client';

import { useRouter, usePathname } from 'next/navigation';
import { revalidatePath } from 'next/cache';

const onChangeHandler = (e: React.ChangeEvent) => {
  const { name, value, checked } = e.target;
  const newValues = checked ? [...checkBoxValues, value] : checkBoxValues.filter((val) => val !== value);

  setCheckBoxValues(newValues);

  if (newValues.length === 0) {
    params.delete(name);
  } else {
    params.set(name, newValues.join("--"));
  }

  const newPath = pathname + (params.toString() ? "?" + params.toString() : "");
  router.push(newPath);
  revalidatePath(newPath);
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 19:50:11